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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_WKBParser.py@2194
Revision 2194, 11.1 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 Well 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 ExceptionWKBParser('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 ExceptionWKBParser(Exception):
90    '''This is the WKB Parser Exception class.'''
91    def __init__(self, value):
92        self.value = value
93    def __str__(self):
94        return `self.value`
95   
96class WKBParser:
97
98    _count = 0
99
100    def __init__(self,factory):
101        """
102        Initialise a new WKBParser.
103
104        (arg factory) an object that implements the methods of OGAbstractFactory.
105        """
106       
107        self._factory = factory
108
109        self._typemap = {6: self.parseMultiPolygon,
110                         1: self.parsePoint,
111                         2: self.parseLineString,
112                         3: self.parsePolygon,
113                         4: self.parseMultiPoint,
114                         5: self.parseMultiLineString,
115                         7: self.parseGeometryCollection}
116       
117       
118    def parseGeometry(self, geometry):
119       
120
121        """
122        A factory method for creating objects of the correct OpenGIS type.
123        """
124
125        # Used for exception strings
126        self._current_string = geometry
127
128        self._factory.beginWork()
129       
130        reader = _ExtendedUnPacker(geometry)
131       
132        self._factory.beginUnit(None) # The WKB format does not have the SRID
133
134        # Start the parsing
135        self._dispatchNextType(reader)
136       
137        self._factory.endUnit()
138        self._factory.endWork()
139
140
141    def _dispatchNextType(self,reader):
142        """
143        Read a type id from the binary stream (reader) and call the correct method to parse it.
144        """
145        # Need to check endianess here!
146        endianness = reader.unpack_byte()
147        if endianness == 0:
148            reader.setEndianness('XDR')
149        elif endianness == 1:
150            reader.setEndianness('NDR')
151        else:
152            raise ExceptionWKBParser("Invalid endianness in WKB format.\n"\
153                                     "The parser can only cope with XDR/big endian WKB format.\n"\
154                                     "To force the WKB format to be in XDR use AsBinary(<fieldname>,'XDR'")
155           
156       
157        geotype = reader.unpack_uint32()
158        mask = geotype & 0x8000 # This is used to mask of the dimension flag.
159
160        dimensions = 2
161        if mask == 0:
162            dimensions = 2
163        elif mask == 0x8000:
164            dimensions = 3
165            geotype = geotype - 0x8000
166
167        else:
168            raise ExceptionWKBParser('Invalid dimension mask in WKB string: %s' % (str(self._current_string),))
169
170        # Despatch to a method on the type id.
171        if self._typemap.has_key(geotype):
172            self._typemap[geotype](reader, dimensions)
173        else:
174            raise ExceptionWKBParser('Error type to dispatch with geotype = %s \n'\
175                                     'Invalid geometry in WKB string: %s' % (str(geotype),
176                                                                             str(self._current_string),))
177       
178    def parseGeometryCollection(self, reader, dimension):
179        self._factory.beginGeometryCollection()
180       
181                       
182        try:
183            num_geoms = reader.unpack_uint32()
184
185            for geom in xrange(0,num_geoms):
186                self._dispatchNextType(reader)
187
188        except:
189            type, value, tb = sys.exc_info()[:3]
190            error = ("%s , %s \n" % (type, value))
191            for bits in traceback.format_exception(type,value,tb):
192                error = error + bits + '\n'
193            del tb
194            self._factory.abortLineString()
195            raise ExceptionWKBParser("Caught unhandled exception parsing GeometryCollection: %s \n"\
196                                     "Traceback: %s\n" % (str(self._current_string),error))
197       
198   
199        self._factory.endGeometryCollection()
200       
201    def parseLinearRing(self, reader, dimensions):
202        self._factory.beginLinearRing()
203       
204        try:
205            num_points = reader.unpack_uint32()
206
207            for point in xrange(0,num_points):
208                self.parsePoint(reader,dimensions)
209
210        except:
211            type, value, tb = sys.exc_info()[:3]
212            error = ("%s , %s \n" % (type, value))
213            for bits in traceback.format_exception(type,value,tb):
214                error = error + bits + '\n'
215            del tb
216            self._factory.abortLinearRing()
217            raise ExceptionWKBParser("Caught unhandled exception parsing LinearRing: %s \n"\
218                                     "Traceback: %s\n" % (str(self._current_string),error))
219
220        self._factory.endLinearRing()
221   
222    def parseLineString(self, reader, dimensions):
223        # Linestring is broken in the same way as MultiPoint
224       
225        self._factory.beginLineString()
226
227        try:
228            num_points = reader.unpack_uint32()
229
230            for point in xrange(0,num_points):
231                self.parsePoint(reader,dimensions)
232
233        except:
234            type, value, tb = sys.exc_info()[:3]
235            error = ("%s , %s \n" % (type, value))
236            for bits in traceback.format_exception(type,value,tb):
237                error = error + bits + '\n'
238            del tb
239            self._factory.abortLineString()
240            raise ExceptionWKBParser("Caught unhandled exception parsing Linestring: %s \n"\
241                                     "Traceback: %s\n" % (str(self._current_string),error))
242               
243        self._factory.endLineString()
244   
245    def parseMultiLineString(self, reader, dimensions):
246        self._factory.beginMultiLineString()
247               
248        try:
249            num_linestrings = reader.unpack_uint32()
250
251            for linestring in xrange(0,num_linestrings):
252                self._dispatchNextType(reader)
253
254        except:
255            type, value, tb = sys.exc_info()[:3]
256            error = ("%s , %s \n" % (type, value))
257            for bits in traceback.format_exception(type,value,tb):
258                error = error + bits + '\n'
259            del tb
260            self._factory.abortLineString()
261            raise ExceptionWKBParser("Caught unhandled exception parsing MultiLineString: %s \n"\
262                                     "Traceback: %s\n" % (str(self._current_string),error))
263       
264
265        self._factory.endMultiLineString()
266   
267    def parseMultiPoint(self, reader, dimensions):
268        self._factory.beginMultiPoint()
269
270        try:
271            num_points = reader.unpack_uint32()
272
273            for point in xrange(0,num_points):
274                self._dispatchNextType(reader)
275
276        except:
277            type, value, tb = sys.exc_info()[:3]
278            error = ("%s , %s \n" % (type, value))
279            for bits in traceback.format_exception(type,value,tb):
280                error = error + bits + '\n'
281            del tb
282            self._factory.abortLineString()
283            raise ExceptionWKBParser("Caught unhandled exception parsing MultiPoint: %s \n"\
284                                     "Traceback: %s\n" % (str(self._current_string),error))
285               
286        self._factory.endMultiPoint()
287
288   
289    def parseMultiPolygon(self, reader, dimensions):
290        self._factory.beginMultiPolygon()
291               
292        try:
293            num_polygons = reader.unpack_uint32()
294
295            for polygon in xrange(0,num_polygons):
296                self._dispatchNextType(reader)
297
298        except:
299            type, value, tb = sys.exc_info()[:3]
300            error = ("%s , %s \n" % (type, value))
301            for bits in traceback.format_exception(type,value,tb):
302                error = error + bits + '\n'
303            del tb
304            self._factory.abortLineString()
305            raise ExceptionWKBParser("Caught unhandled exception parsing MultiPolygon: %s \n"\
306                                     "Traceback: %s\n" % (str(self._current_string),error))
307       
308       
309        self._factory.endMultiPolygon()
310   
311    def parsePoint(self, reader, dimensions):
312        self._factory.beginPoint()
313               
314        x = reader.unpack_double()
315        y = reader.unpack_double()
316        if dimensions == 3:
317            z = reader.unpack_double()
318        else:
319            z = None
320
321        if z != None:
322            self._factory.addPoints3D(x,y,z)
323        else:
324            self._factory.addPoints(x,y)
325
326        self._factory.endPoint()
327   
328    def parsePolygon(self, reader, dimensions):
329        self._factory.beginPolygon()
330
331        try:
332            num_points = reader.unpack_uint32()
333
334            for point in xrange(0,num_points):
335                self.parseLinearRing(reader,dimensions)
336
337        except:
338            type, value, tb = sys.exc_info()[:3]
339            error = ("%s , %s \n" % (type, value))
340            for bits in traceback.format_exception(type,value,tb):
341                error = error + bits + '\n'
342            del tb
343            self._factory.abortPolygon()
344            raise ExceptionWKBParser("Caught unhandled exception parsing Polygon: %s \n"\
345                                     "Traceback: %s\n" % (str(self._current_string),error))
346
347        self._factory.endPolygon()
Note: See TracBrowser for help on using the repository browser.