source: TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_EWKBParser.py @ 2194

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_EWKBParser.py@2194
Revision 2194, 12.4 KB checked in by lawrence, 13 years ago (diff)

Adding various specs and 3rd party code of interest for the CSML
services development.

Line 
1
2################################################################################
3# Copyright (c) QinetiQ Plc 2003
4#
5# Licensed under the LGPL. For full license details see the LICENSE file.
6################################################################################
7
8"""
9A parser for the (Extended) Well Formed Text Binary format of OpenGIS types.
10"""
11#
12# 2.5d spec: http://gdal.velocet.ca/projects/opengis/twohalfdsf.html
13#
14
15import shlex, StringIO, sys, traceback, xdrlib, struct
16
17
18# based on xdrlib.Unpacker
19class _ExtendedUnPacker:
20    """
21    A simple binary struct parser, only implements the types that are need for the WKB format.
22    """
23   
24    def __init__(self,data):
25        self.reset(data)
26        self.setEndianness('XDR')
27
28    def reset(self, data):
29        self.__buf = data
30        self.__pos = 0
31
32    def get_position(self):
33        return self.__pos
34
35    def set_position(self, position):
36        self.__pos = position
37
38    def get_buffer(self):
39        return self.__buf
40
41    def done(self):
42        if self.__pos < len(self.__buf):
43            raise Error('unextracted data remains')
44
45    def setEndianness(self,endianness):
46        if endianness == 'XDR':
47            self._endflag = '>'
48        elif endianness == 'NDR':
49            self._endflag = '<'
50        else:
51            raise ExceptionEWKBParser('Attempt to set unknown endianness in ExtendedUnPacker')
52
53    def unpack_byte(self):
54        i = self.__pos
55        self.__pos = j = i+1
56        data = self.__buf[i:j]
57        if len(data) < 1:
58            raise EOFError
59        byte = struct.unpack('%sB' % self._endflag, data)[0]
60        return byte
61
62    def unpack_uint32(self):
63        i = self.__pos
64        self.__pos = j = i+4
65        data = self.__buf[i:j]
66        if len(data) < 4:
67            raise EOFError
68        uint32 = struct.unpack('%si' % self._endflag, data)[0]
69        return uint32
70
71
72    def unpack_short(self):
73        i = self.__pos
74        self.__pos = j = i+2
75        data = self.__buf[i:j]
76        if len(data) < 2:
77            raise EOFError
78        short = struct.unpack('%sH' % self._endflag, data)[0]
79        return short
80
81    def unpack_double(self):
82        i = self.__pos
83        self.__pos = j = i+8
84        data = self.__buf[i:j]
85        if len(data) < 8:
86            raise EOFError
87        return struct.unpack('%sd' % self._endflag, data)[0]
88
89class ExceptionEWKBParser(Exception):
90    '''This is the EWKB Parser Exception class.'''
91    def __init__(self, value):
92        self.value = value
93    def __str__(self):
94        return `self.value`
95   
96class EWKBParser:
97
98    _count = 0
99   
100    # these masks are or'd with the type
101    _z_mask = 0x80000000 # to indicate presence of z dimension
102    _m_mask = 0x40000000 # to indicate presence of measurement
103    _s_mask = 0x20000000 # to indicate presence of SRID
104
105    def __init__(self,factory):
106        """
107        Initialise a new WKBParser.
108
109        (arg factory) an object that implements the methods of OGAbstractFactory.
110        """
111       
112        self._factory = factory
113
114        self._typemap = {6: self.parseMultiPolygon,
115                         1: self.parsePoint,
116                         2: self.parseLineString,
117                         3: self.parsePolygon,
118                         4: self.parseMultiPoint,
119                         5: self.parseMultiLineString,
120                         7: self.parseGeometryCollection}
121       
122       
123    def parseGeometry(self, geometry):
124       
125
126        """
127        A factory method for creating objects of the correct OpenGIS type.
128        """
129
130        # Used for exception strings
131        self._current_string = geometry
132
133        self._factory.beginWork()
134       
135        reader = _ExtendedUnPacker(geometry)
136       
137        self._factory.beginUnit(None) # The WKB format does not have the SRID
138
139        # Start the parsing
140        self._dispatchNextType(reader)
141       
142        self._factory.endUnit()
143        self._factory.endWork()
144
145
146    def _dispatchNextType(self,reader):
147        """
148        Read a type id from the binary stream (reader) and call the correct method to parse it.
149        """
150        # Need to check endianess here!
151        endianness = reader.unpack_byte()
152        if endianness == 0:
153            reader.setEndianness('XDR')
154        elif endianness == 1:
155            reader.setEndianness('NDR')
156        else:
157            raise ExceptionEWKBParser("Invalid endianness in WKB format.\n"\
158                                     "The parser can only cope with XDR/big endian WKB format.\n"\
159                                     "To force the WKB format to be in XDR use AsBinary(<fieldname>,'XDR'")
160                   
161        geotype = reader.unpack_uint32()
162
163        if geotype & EWKBParser._z_mask:
164            dimensions = 3
165            geotype = geotype & (~EWKBParser._z_mask)
166        else:
167            dimensions = 2
168           
169        if geotype & EWKBParser._m_mask:
170            geotype = geotype & (~EWKBParser._m_mask)
171            raise ExceptionEWKBParser('Error: Geometry has M dimension. \n'\
172                                      'GeoTypes does not yet support M dimension types. \n'\
173                                      'type = %s \n'\
174                                     'Invalid geometry in WKB string: %s' % (str(geotype),
175                                                                             str(self._current_string),))
176
177           
178        if geotype & EWKBParser._s_mask:
179            srid = reader.unpack_uint32()
180            geotype = geotype & (~EWKBParser._s_mask)
181        else:
182            srid = None
183
184
185        # Despatch to a method on the type id.
186        if self._typemap.has_key(geotype):
187            self._typemap[geotype](reader, dimensions, srid)
188        else:
189            raise ExceptionEWKBParser('Error type to dispatch with geotype = %s \n'\
190                                     'Invalid geometry in WKB string: %s' % (str(geotype),
191                                                                             str(self._current_string),))
192       
193    def parseGeometryCollection(self, reader, dimension, srid):
194        self._factory.beginGeometryCollection(srid)
195       
196                       
197        try:
198            num_geoms = reader.unpack_uint32()
199
200            for geom in xrange(0,num_geoms):
201                self._dispatchNextType(reader)
202
203        except:
204            type, value, tb = sys.exc_info()[:3]
205            error = ("%s , %s \n" % (type, value))
206            for bits in traceback.format_exception(type,value,tb):
207                error = error + bits + '\n'
208            del tb
209            self._factory.abortLineString()
210            raise ExceptionEWKBParser("Caught unhandled exception parsing GeometryCollection: %s \n"\
211                                     "Traceback: %s\n" % (str(self._current_string),error))
212       
213   
214        self._factory.endGeometryCollection()
215       
216    def parseLinearRing(self, reader, dimensions, srid):
217        self._factory.beginLinearRing(srid)
218       
219        try:
220            num_points = reader.unpack_uint32()
221
222            for point in xrange(0,num_points):
223                self.parsePoint(reader,dimensions,srid)
224
225        except:
226            type, value, tb = sys.exc_info()[:3]
227            error = ("%s , %s \n" % (type, value))
228            for bits in traceback.format_exception(type,value,tb):
229                error = error + bits + '\n'
230            del tb
231            self._factory.abortLinearRing()
232            raise ExceptionEWKBParser("Caught unhandled exception parsing LinearRing: %s \n"\
233                                     "Traceback: %s\n" % (str(self._current_string),error))
234
235        self._factory.endLinearRing()
236   
237    def parseLineString(self, reader, dimensions, srid):
238        # Linestring is broken in the same way as MultiPoint
239       
240        self._factory.beginLineString(srid)
241
242        try:
243            num_points = reader.unpack_uint32()
244
245            for point in xrange(0,num_points):
246                self.parsePoint(reader,dimensions,srid)
247
248        except:
249            type, value, tb = sys.exc_info()[:3]
250            error = ("%s , %s \n" % (type, value))
251            for bits in traceback.format_exception(type,value,tb):
252                error = error + bits + '\n'
253            del tb
254            self._factory.abortLineString()
255            raise ExceptionEWKBParser("Caught unhandled exception parsing Linestring: %s \n"\
256                                     "Traceback: %s\n" % (str(self._current_string),error))
257               
258        self._factory.endLineString()
259   
260    def parseMultiLineString(self, reader, dimensions, srid):
261        self._factory.beginMultiLineString(srid)
262               
263        try:
264            num_linestrings = reader.unpack_uint32()
265
266            for linestring in xrange(0,num_linestrings):
267                self._dispatchNextType(reader)
268
269        except:
270            type, value, tb = sys.exc_info()[:3]
271            error = ("%s , %s \n" % (type, value))
272            for bits in traceback.format_exception(type,value,tb):
273                error = error + bits + '\n'
274            del tb
275            self._factory.abortLineString()
276            raise ExceptionEWKBParser("Caught unhandled exception parsing MultiLineString: %s \n"\
277                                     "Traceback: %s\n" % (str(self._current_string),error))
278       
279
280        self._factory.endMultiLineString()
281   
282    def parseMultiPoint(self, reader, dimensions, srid):
283        self._factory.beginMultiPoint(srid)
284
285        try:
286            num_points = reader.unpack_uint32()
287
288            for point in xrange(0,num_points):
289                self._dispatchNextType(reader)
290
291        except:
292            type, value, tb = sys.exc_info()[:3]
293            error = ("%s , %s \n" % (type, value))
294            for bits in traceback.format_exception(type,value,tb):
295                error = error + bits + '\n'
296            del tb
297            self._factory.abortLineString()
298            raise ExceptionEWKBParser("Caught unhandled exception parsing MultiPoint: %s \n"\
299                                     "Traceback: %s\n" % (str(self._current_string),error))
300               
301        self._factory.endMultiPoint()
302
303   
304    def parseMultiPolygon(self, reader, dimensions, srid):
305        self._factory.beginMultiPolygon(srid)
306               
307        try:
308            num_polygons = reader.unpack_uint32()
309
310            for polygon in xrange(0,num_polygons):
311                self._dispatchNextType(reader)
312
313        except:
314            type, value, tb = sys.exc_info()[:3]
315            error = ("%s , %s \n" % (type, value))
316            for bits in traceback.format_exception(type,value,tb):
317                error = error + bits + '\n'
318            del tb
319            self._factory.abortLineString()
320            raise ExceptionEWKBParser("Caught unhandled exception parsing MultiPolygon: %s \n"\
321                                     "Traceback: %s\n" % (str(self._current_string),error))
322       
323       
324        self._factory.endMultiPolygon()
325   
326    def parsePoint(self, reader, dimensions, srid):
327        self._factory.beginPoint(srid)
328               
329        x = reader.unpack_double()
330        y = reader.unpack_double()
331        if dimensions == 3:
332            z = reader.unpack_double()
333        else:
334            z = None
335
336        if z != None:
337            self._factory.addPoints3D(x,y,z)
338        else:
339            self._factory.addPoints(x,y)
340
341        self._factory.endPoint()
342   
343    def parsePolygon(self, reader, dimensions, srid):
344        self._factory.beginPolygon(srid)
345
346        try:
347            num_points = reader.unpack_uint32()
348
349            for point in xrange(0,num_points):
350                self.parseLinearRing(reader,dimensions, srid)
351
352        except:
353            type, value, tb = sys.exc_info()[:3]
354            error = ("%s , %s \n" % (type, value))
355            for bits in traceback.format_exception(type,value,tb):
356                error = error + bits + '\n'
357            del tb
358            self._factory.abortPolygon()
359            raise ExceptionEWKBParser("Caught unhandled exception parsing Polygon: %s \n"\
360                                     "Traceback: %s\n" % (str(self._current_string),error))
361
362        self._factory.endPolygon()
363
364class HEXEWKBParser(EWKBParser):
365
366    def __init__(self,factory):
367        """
368        Initialise a new WKBParser.
369
370        (arg factory) an object that implements the methods of OGAbstractFactory.
371        """
372        EWKBParser.__init__(self,factory)
373       
374       
375    def parseGeometry(self, geometry):
376       
377
378        """
379        A factory method for creating objects of the correct OpenGIS type.
380        """
381
382        EWKBParser.parseGeometry(self,geometry.decode('hex'))
Note: See TracBrowser for help on using the repository browser.