1 : /******************************************************************************
2 : * $Id: ogrmssqlgeometryparser.cpp 20591 2010-09-12 17:27:42Z tamas $
3 : *
4 : * Project: MSSQL Spatial driver
5 : * Purpose: Implements OGRMSSQLGeometryParser class to parse native SqlGeometries.
6 : * Author: Tamas Szekeres, szekerest at gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Tamas Szekeres
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_conv.h"
31 : #include "ogr_mssqlspatial.h"
32 :
33 : CPL_CVSID("$Id: ogrmssqlgeometryparser.cpp 20591 2010-09-12 17:27:42Z tamas $");
34 :
35 : /************************************************************************/
36 : /* Geometry parser macros */
37 : /************************************************************************/
38 :
39 : #define SP_NONE 0
40 : #define SP_HASZVALUES 1
41 : #define SP_HASMVALUES 2
42 : #define SP_ISVALID 4
43 : #define SP_ISSINGLEPOINT 8
44 : #define SP_ISSINGLELINESEGMENT 0x10
45 : #define SP_ISWHOLEGLOBE 0x20
46 :
47 : #define ST_UNKNOWN 0
48 : #define ST_POINT 1
49 : #define ST_LINESTRING 2
50 : #define ST_POLYGON 3
51 : #define ST_MULTIPOINT 4
52 : #define ST_MULTILINESTRING 5
53 : #define ST_MULTIPOLYGON 6
54 : #define ST_GEOMETRYCOLLECTION 7
55 :
56 : #define ReadInt32(nPos) (*((unsigned int*)(pszData + (nPos))))
57 :
58 : #define ReadByte(nPos) (pszData[nPos])
59 :
60 : #define ReadDouble(nPos) (*((double*)(pszData + (nPos))))
61 :
62 : #define ParentOffset(iShape) (ReadInt32(nShapePos + (iShape) * 9 ))
63 : #define FigureOffset(iShape) (ReadInt32(nShapePos + (iShape) * 9 + 4))
64 : #define ShapeType(iShape) (ReadByte(nShapePos + (iShape) * 9 + 8))
65 :
66 : #define NextFigureOffset(iShape) (iShape + 1 < nNumShapes? FigureOffset((iShape) +1) : nNumFigures)
67 :
68 : #define FigureAttribute(iFigure) (ReadByte(nFigurePos + (iFigure) * 5))
69 : #define PointOffset(iFigure) (ReadInt32(nFigurePos + (iFigure) * 5 + 1))
70 : #define NextPointOffset(iFigure) (iFigure + 1 < nNumFigures? PointOffset((iFigure) +1) : nNumPoints)
71 :
72 : #define ReadX(iPoint) (ReadDouble(nPointPos + nPointSize * (iPoint)))
73 : #define ReadY(iPoint) (ReadDouble(nPointPos + nPointSize * (iPoint) + 8))
74 : #define ReadZ(iPoint) (ReadDouble(nPointPos + nPointSize * (iPoint) + 16))
75 :
76 : /************************************************************************/
77 : /* OGRMSSQLGeometryParser() */
78 : /************************************************************************/
79 :
80 0 : OGRMSSQLGeometryParser::OGRMSSQLGeometryParser()
81 : {
82 0 : }
83 :
84 : /************************************************************************/
85 : /* ReadPoint() */
86 : /************************************************************************/
87 :
88 0 : OGRPoint* OGRMSSQLGeometryParser::ReadPoint(int iShape)
89 : {
90 0 : int iFigure = FigureOffset(iShape);
91 0 : if ( iFigure < nNumFigures )
92 : {
93 0 : int iPoint = PointOffset(iFigure);
94 0 : if ( iPoint < nNumPoints )
95 : {
96 0 : if ( chProps & SP_HASZVALUES )
97 0 : return new OGRPoint( ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
98 : else
99 0 : return new OGRPoint( ReadX(iPoint), ReadY(iPoint) );
100 : }
101 : }
102 0 : return NULL;
103 : }
104 :
105 : /************************************************************************/
106 : /* ReadMultiPoint() */
107 : /************************************************************************/
108 :
109 0 : OGRMultiPoint* OGRMSSQLGeometryParser::ReadMultiPoint(int iShape)
110 : {
111 : int iFigure, iPoint, iNextPoint;
112 0 : iFigure = FigureOffset(iShape);
113 :
114 0 : OGRMultiPoint* poMultiPoint = new OGRMultiPoint();
115 0 : iNextPoint = NextPointOffset(iFigure);
116 0 : for (iPoint = PointOffset(iFigure); iPoint < iNextPoint; iPoint++)
117 : {
118 : OGRPoint* poPoint;
119 :
120 0 : if ( chProps & SP_HASZVALUES )
121 0 : poPoint = new OGRPoint( ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
122 : else
123 0 : poPoint = new OGRPoint( ReadX(iPoint), ReadY(iPoint) );
124 :
125 0 : if ( poPoint )
126 0 : poMultiPoint->addGeometryDirectly( poPoint );
127 : }
128 :
129 0 : return poMultiPoint;
130 : }
131 :
132 : /************************************************************************/
133 : /* ReadLineString() */
134 : /************************************************************************/
135 :
136 0 : OGRLineString* OGRMSSQLGeometryParser::ReadLineString(int iShape)
137 : {
138 : int iFigure, iPoint, iNextPoint, i;
139 0 : iFigure = FigureOffset(iShape);
140 :
141 0 : OGRLineString* poLineString = new OGRLineString();
142 0 : iPoint = PointOffset(iFigure);
143 0 : iNextPoint = NextPointOffset(iFigure);
144 0 : poLineString->setNumPoints(iNextPoint - iPoint);
145 0 : i = 0;
146 0 : while (iPoint < iNextPoint)
147 : {
148 0 : if ( chProps & SP_HASZVALUES )
149 0 : poLineString->setPoint(i, ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
150 : else
151 0 : poLineString->setPoint(i, ReadX(iPoint), ReadY(iPoint) );
152 :
153 0 : ++iPoint;
154 0 : ++i;
155 : }
156 :
157 0 : return poLineString;
158 : }
159 :
160 : /************************************************************************/
161 : /* ReadMultiLineString() */
162 : /************************************************************************/
163 :
164 0 : OGRMultiLineString* OGRMSSQLGeometryParser::ReadMultiLineString(int iShape)
165 : {
166 : int i;
167 0 : OGRMultiLineString* poMultiLineString = new OGRMultiLineString();
168 : OGRGeometry* poGeom;
169 :
170 0 : for (i = iShape + 1; i < nNumShapes; i++)
171 : {
172 0 : poGeom = NULL;
173 0 : if (ParentOffset(i) == (unsigned int)iShape)
174 : {
175 0 : if ( ShapeType(i) == ST_LINESTRING )
176 0 : poGeom = ReadLineString(i);
177 : }
178 0 : if ( poGeom )
179 0 : poMultiLineString->addGeometryDirectly( poGeom );
180 : }
181 :
182 0 : return poMultiLineString;
183 : }
184 :
185 : /************************************************************************/
186 : /* ReadPolygon() */
187 : /************************************************************************/
188 :
189 0 : OGRPolygon* OGRMSSQLGeometryParser::ReadPolygon(int iShape)
190 : {
191 : int iFigure, iPoint, iNextPoint, i;
192 0 : int iNextFigure = NextFigureOffset(iShape);
193 :
194 0 : OGRPolygon* poPoly = new OGRPolygon();
195 0 : for (iFigure = FigureOffset(iShape); iFigure < iNextFigure; iFigure++)
196 : {
197 0 : OGRLinearRing* poRing = new OGRLinearRing();
198 0 : iPoint = PointOffset(iFigure);
199 0 : iNextPoint = NextPointOffset(iFigure);
200 0 : poRing->setNumPoints(iNextPoint - iPoint);
201 0 : i = 0;
202 0 : while (iPoint < iNextPoint)
203 : {
204 0 : if ( chProps & SP_HASZVALUES )
205 0 : poRing->setPoint(i, ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
206 : else
207 0 : poRing->setPoint(i, ReadX(iPoint), ReadY(iPoint) );
208 :
209 0 : ++iPoint;
210 0 : ++i;
211 : }
212 0 : poPoly->addRingDirectly( poRing );
213 : }
214 0 : return poPoly;
215 : }
216 :
217 : /************************************************************************/
218 : /* ReadMultiPolygon() */
219 : /************************************************************************/
220 :
221 0 : OGRMultiPolygon* OGRMSSQLGeometryParser::ReadMultiPolygon(int iShape)
222 : {
223 : int i;
224 0 : OGRMultiPolygon* poMultiPolygon = new OGRMultiPolygon();
225 : OGRGeometry* poGeom;
226 :
227 0 : for (i = iShape + 1; i < nNumShapes; i++)
228 : {
229 0 : poGeom = NULL;
230 0 : if (ParentOffset(i) == (unsigned int)iShape)
231 : {
232 0 : if ( ShapeType(i) == ST_POLYGON )
233 0 : poGeom = ReadPolygon(i);
234 : }
235 0 : if ( poGeom )
236 0 : poMultiPolygon->addGeometryDirectly( poGeom );
237 : }
238 :
239 0 : return poMultiPolygon;
240 : }
241 :
242 : /************************************************************************/
243 : /* ReadGeometryCollection() */
244 : /************************************************************************/
245 :
246 0 : OGRGeometryCollection* OGRMSSQLGeometryParser::ReadGeometryCollection(int iShape)
247 : {
248 : int i;
249 0 : OGRGeometryCollection* poGeomColl = new OGRGeometryCollection();
250 : OGRGeometry* poGeom;
251 :
252 0 : for (i = iShape + 1; i < nNumShapes; i++)
253 : {
254 0 : poGeom = NULL;
255 0 : if (ParentOffset(i) == (unsigned int)iShape)
256 : {
257 0 : switch (ShapeType(i))
258 : {
259 : case ST_POINT:
260 0 : poGeom = ReadPoint(i);
261 0 : break;
262 : case ST_LINESTRING:
263 0 : poGeom = ReadLineString(i);
264 0 : break;
265 : case ST_POLYGON:
266 0 : poGeom = ReadPolygon(i);
267 0 : break;
268 : case ST_MULTIPOINT:
269 0 : poGeom = ReadMultiPoint(i);
270 0 : break;
271 : case ST_MULTILINESTRING:
272 0 : poGeom = ReadMultiLineString(i);
273 0 : break;
274 : case ST_MULTIPOLYGON:
275 0 : poGeom = ReadMultiPolygon(i);
276 0 : break;
277 : case ST_GEOMETRYCOLLECTION:
278 0 : poGeom = ReadGeometryCollection(i);
279 : break;
280 : }
281 : }
282 0 : if ( poGeom )
283 0 : poGeomColl->addGeometryDirectly( poGeom );
284 : }
285 :
286 0 : return poGeomColl;
287 : }
288 :
289 : /************************************************************************/
290 : /* ParseSqlGeometry() */
291 : /************************************************************************/
292 :
293 :
294 0 : OGRErr OGRMSSQLGeometryParser::ParseSqlGeometry(unsigned char* pszInput,
295 : int nLen, OGRGeometry **poGeom)
296 : {
297 0 : if (nLen < 10)
298 0 : return OGRERR_NOT_ENOUGH_DATA;
299 :
300 0 : pszData = pszInput;
301 :
302 : /* store the SRS id for further use */
303 0 : nSRSId = ReadInt32(0);
304 :
305 0 : if ( ReadByte(4) != 1 )
306 : {
307 0 : return OGRERR_CORRUPT_DATA;
308 : }
309 :
310 0 : chProps = ReadByte(5);
311 :
312 0 : if ( chProps & SP_HASMVALUES )
313 0 : nPointSize = 32;
314 0 : else if ( chProps & SP_HASZVALUES )
315 0 : nPointSize = 24;
316 : else
317 0 : nPointSize = 16;
318 :
319 0 : if ( chProps & SP_ISSINGLEPOINT )
320 : {
321 : // single point geometry
322 0 : nPointPos = 6;
323 :
324 0 : if (nLen < 6 + nPointSize)
325 : {
326 0 : return OGRERR_NOT_ENOUGH_DATA;
327 : }
328 :
329 0 : if (chProps & SP_HASZVALUES)
330 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0), ReadZ(0));
331 : else
332 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0));
333 : }
334 0 : else if ( chProps & SP_ISSINGLELINESEGMENT )
335 : {
336 : // single line segment with 2 points
337 0 : nPointPos = 6;
338 :
339 0 : if (nLen < 6 + 2 * nPointSize)
340 : {
341 0 : return OGRERR_NOT_ENOUGH_DATA;
342 : }
343 :
344 0 : OGRLineString* line = new OGRLineString();
345 0 : line->setNumPoints(2);
346 :
347 0 : if ( chProps & SP_HASZVALUES )
348 : {
349 0 : line->setPoint(0, ReadX(0), ReadY(0), ReadZ(0));
350 0 : line->setPoint(1, ReadX(1), ReadY(1), ReadZ(1));
351 : }
352 : else
353 : {
354 0 : line->setPoint(0, ReadX(0), ReadY(0));
355 0 : line->setPoint(1, ReadX(1), ReadY(1));
356 : }
357 :
358 0 : *poGeom = line;
359 : }
360 : else
361 : {
362 : // complex geometries
363 0 : nNumPoints = ReadInt32(6);
364 :
365 0 : if ( nNumPoints <= 0 )
366 : {
367 0 : return OGRERR_NONE;
368 : }
369 :
370 : // position of the point array
371 0 : nPointPos = 10;
372 :
373 : // position of the figures
374 0 : nFigurePos = nPointPos + nPointSize * nNumPoints + 4;
375 :
376 0 : if (nLen < nFigurePos)
377 : {
378 0 : return OGRERR_NOT_ENOUGH_DATA;
379 : }
380 :
381 0 : nNumFigures = ReadInt32(nFigurePos - 4);
382 :
383 0 : if ( nNumFigures <= 0 )
384 : {
385 0 : return OGRERR_NONE;
386 : }
387 :
388 : // position of the shapes
389 0 : nShapePos = nFigurePos + 5 * nNumFigures + 4;
390 :
391 0 : if (nLen < nShapePos)
392 : {
393 0 : return OGRERR_NOT_ENOUGH_DATA;
394 : }
395 :
396 0 : nNumShapes = ReadInt32(nShapePos - 4);
397 :
398 0 : if (nLen < nShapePos + 9 * nNumShapes)
399 : {
400 0 : return OGRERR_NOT_ENOUGH_DATA;
401 : }
402 :
403 0 : if ( nNumShapes <= 0 )
404 : {
405 0 : return OGRERR_NONE;
406 : }
407 :
408 : // pick up the root shape
409 0 : if ( ParentOffset(0) != 0xFFFFFFFF)
410 : {
411 0 : return OGRERR_CORRUPT_DATA;
412 : }
413 :
414 : // determine the shape type
415 0 : switch (ShapeType(0))
416 : {
417 : case ST_POINT:
418 0 : *poGeom = ReadPoint(0);
419 0 : break;
420 : case ST_LINESTRING:
421 0 : *poGeom = ReadLineString(0);
422 0 : break;
423 : case ST_POLYGON:
424 0 : *poGeom = ReadPolygon(0);
425 0 : break;
426 : case ST_MULTIPOINT:
427 0 : *poGeom = ReadMultiPoint(0);
428 0 : break;
429 : case ST_MULTILINESTRING:
430 0 : *poGeom = ReadMultiLineString(0);
431 0 : break;
432 : case ST_MULTIPOLYGON:
433 0 : *poGeom = ReadMultiPolygon(0);
434 0 : break;
435 : case ST_GEOMETRYCOLLECTION:
436 0 : *poGeom = ReadGeometryCollection(0);
437 0 : break;
438 : default:
439 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
440 : }
441 : }
442 :
443 0 : return OGRERR_NONE;
444 : }
445 :
|