1 : /******************************************************************************
2 : * $Id: ogrmssqlgeometryparser.cpp 24918 2012-09-07 12:02:01Z 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 24918 2012-09-07 12:02:01Z tamas $");
34 :
35 : /* SqlGeometry serialization format
36 :
37 : Simple Point (SerializationProps & IsSinglePoint)
38 : [SRID][0x01][SerializationProps][Point][z][m]
39 :
40 : Simple Line Segment (SerializationProps & IsSingleLineSegment)
41 : [SRID][0x01][SerializationProps][Point1][Point2][z1][z2][m1][m2]
42 :
43 : Complex Geometries
44 : [SRID][0x01][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN]
45 : [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape]
46 :
47 : SRID
48 : Spatial Reference Id (4 bytes)
49 :
50 : SerializationProps (bitmask) 1 byte
51 : 0x01 = HasZValues
52 : 0x02 = HasMValues
53 : 0x04 = IsValid
54 : 0x08 = IsSinglePoint
55 : 0x10 = IsSingleLineSegment
56 : 0x20 = IsWholeGlobe
57 :
58 : Point (2-4)x8 bytes, size depends on SerializationProps & HasZValues & HasMValues
59 : [x][y] - SqlGeometry
60 : [latitude][longitude] - SqlGeography
61 :
62 : Figure
63 : [FigureAttribute][PointOffset]
64 :
65 : FigureAttribute (1 byte)
66 : 0x00 = Interior Ring
67 : 0x01 = Stroke
68 : 0x02 = Exterior Ring
69 :
70 : Shape
71 : [ParentFigureOffset][FigureOffset][ShapeType]
72 :
73 : ShapeType (1 byte)
74 : 0x00 = Unknown
75 : 0x01 = Point
76 : 0x02 = LineString
77 : 0x03 = Polygon
78 : 0x04 = MultiPoint
79 : 0x05 = MultiLineString
80 : 0x06 = MultiPolygon
81 : 0x07 = GeometryCollection
82 :
83 : */
84 :
85 : /************************************************************************/
86 : /* Geometry parser macros */
87 : /************************************************************************/
88 :
89 : #define SP_NONE 0
90 : #define SP_HASZVALUES 1
91 : #define SP_HASMVALUES 2
92 : #define SP_ISVALID 4
93 : #define SP_ISSINGLEPOINT 8
94 : #define SP_ISSINGLELINESEGMENT 0x10
95 : #define SP_ISWHOLEGLOBE 0x20
96 :
97 : #define ST_UNKNOWN 0
98 : #define ST_POINT 1
99 : #define ST_LINESTRING 2
100 : #define ST_POLYGON 3
101 : #define ST_MULTIPOINT 4
102 : #define ST_MULTILINESTRING 5
103 : #define ST_MULTIPOLYGON 6
104 : #define ST_GEOMETRYCOLLECTION 7
105 :
106 : #define ReadInt32(nPos) (*((unsigned int*)(pszData + (nPos))))
107 :
108 : #define ReadByte(nPos) (pszData[nPos])
109 :
110 : #define ReadDouble(nPos) (*((double*)(pszData + (nPos))))
111 :
112 : #define ParentOffset(iShape) (ReadInt32(nShapePos + (iShape) * 9 ))
113 : #define FigureOffset(iShape) (ReadInt32(nShapePos + (iShape) * 9 + 4))
114 : #define ShapeType(iShape) (ReadByte(nShapePos + (iShape) * 9 + 8))
115 :
116 : #define NextFigureOffset(iShape) (iShape + 1 < nNumShapes? FigureOffset((iShape) +1) : nNumFigures)
117 :
118 : #define FigureAttribute(iFigure) (ReadByte(nFigurePos + (iFigure) * 5))
119 : #define PointOffset(iFigure) (ReadInt32(nFigurePos + (iFigure) * 5 + 1))
120 : #define NextPointOffset(iFigure) (iFigure + 1 < nNumFigures? PointOffset((iFigure) +1) : nNumPoints)
121 :
122 : #define ReadX(iPoint) (ReadDouble(nPointPos + 16 * (iPoint)))
123 : #define ReadY(iPoint) (ReadDouble(nPointPos + 16 * (iPoint) + 8))
124 : #define ReadZ(iPoint) (ReadDouble(nPointPos + 16 * nNumPoints + 8 * (iPoint)))
125 : #define ReadM(iPoint) (ReadDouble(nPointPos + 24 * nNumPoints + 8 * (iPoint)))
126 :
127 : /************************************************************************/
128 : /* OGRMSSQLGeometryParser() */
129 : /************************************************************************/
130 :
131 0 : OGRMSSQLGeometryParser::OGRMSSQLGeometryParser(int nGeomColumnType)
132 : {
133 0 : nColType = nGeomColumnType;
134 0 : }
135 :
136 : /************************************************************************/
137 : /* ReadPoint() */
138 : /************************************************************************/
139 :
140 0 : OGRPoint* OGRMSSQLGeometryParser::ReadPoint(int iShape)
141 : {
142 0 : int iFigure = FigureOffset(iShape);
143 0 : if ( iFigure < nNumFigures )
144 : {
145 0 : int iPoint = PointOffset(iFigure);
146 0 : if ( iPoint < nNumPoints )
147 : {
148 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
149 : {
150 0 : if ( chProps & SP_HASZVALUES )
151 0 : return new OGRPoint( ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
152 : else
153 0 : return new OGRPoint( ReadY(iPoint), ReadX(iPoint) );
154 : }
155 : else
156 : {
157 0 : if ( chProps & SP_HASZVALUES )
158 0 : return new OGRPoint( ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
159 : else
160 0 : return new OGRPoint( ReadX(iPoint), ReadY(iPoint) );
161 : }
162 : }
163 : }
164 0 : return NULL;
165 : }
166 :
167 : /************************************************************************/
168 : /* ReadMultiPoint() */
169 : /************************************************************************/
170 :
171 0 : OGRMultiPoint* OGRMSSQLGeometryParser::ReadMultiPoint(int iShape)
172 : {
173 : int i;
174 0 : OGRMultiPoint* poMultiPoint = new OGRMultiPoint();
175 : OGRGeometry* poGeom;
176 :
177 0 : for (i = iShape + 1; i < nNumShapes; i++)
178 : {
179 0 : poGeom = NULL;
180 0 : if (ParentOffset(i) == (unsigned int)iShape)
181 : {
182 0 : if ( ShapeType(i) == ST_POINT )
183 0 : poGeom = ReadPoint(i);
184 : }
185 0 : if ( poGeom )
186 0 : poMultiPoint->addGeometryDirectly( poGeom );
187 : }
188 :
189 0 : return poMultiPoint;
190 : }
191 :
192 : /************************************************************************/
193 : /* ReadLineString() */
194 : /************************************************************************/
195 :
196 0 : OGRLineString* OGRMSSQLGeometryParser::ReadLineString(int iShape)
197 : {
198 : int iFigure, iPoint, iNextPoint, i;
199 0 : iFigure = FigureOffset(iShape);
200 :
201 0 : OGRLineString* poLineString = new OGRLineString();
202 0 : iPoint = PointOffset(iFigure);
203 0 : iNextPoint = NextPointOffset(iFigure);
204 0 : poLineString->setNumPoints(iNextPoint - iPoint);
205 0 : i = 0;
206 0 : while (iPoint < iNextPoint)
207 : {
208 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
209 : {
210 0 : if ( chProps & SP_HASZVALUES )
211 0 : poLineString->setPoint(i, ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
212 : else
213 0 : poLineString->setPoint(i, ReadY(iPoint), ReadX(iPoint) );
214 : }
215 : else
216 : {
217 0 : if ( chProps & SP_HASZVALUES )
218 0 : poLineString->setPoint(i, ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
219 : else
220 0 : poLineString->setPoint(i, ReadX(iPoint), ReadY(iPoint) );
221 : }
222 :
223 0 : ++iPoint;
224 0 : ++i;
225 : }
226 :
227 0 : return poLineString;
228 : }
229 :
230 : /************************************************************************/
231 : /* ReadMultiLineString() */
232 : /************************************************************************/
233 :
234 0 : OGRMultiLineString* OGRMSSQLGeometryParser::ReadMultiLineString(int iShape)
235 : {
236 : int i;
237 0 : OGRMultiLineString* poMultiLineString = new OGRMultiLineString();
238 : OGRGeometry* poGeom;
239 :
240 0 : for (i = iShape + 1; i < nNumShapes; i++)
241 : {
242 0 : poGeom = NULL;
243 0 : if (ParentOffset(i) == (unsigned int)iShape)
244 : {
245 0 : if ( ShapeType(i) == ST_LINESTRING )
246 0 : poGeom = ReadLineString(i);
247 : }
248 0 : if ( poGeom )
249 0 : poMultiLineString->addGeometryDirectly( poGeom );
250 : }
251 :
252 0 : return poMultiLineString;
253 : }
254 :
255 : /************************************************************************/
256 : /* ReadPolygon() */
257 : /************************************************************************/
258 :
259 0 : OGRPolygon* OGRMSSQLGeometryParser::ReadPolygon(int iShape)
260 : {
261 : int iFigure, iPoint, iNextPoint, i;
262 0 : int iNextFigure = NextFigureOffset(iShape);
263 :
264 0 : OGRPolygon* poPoly = new OGRPolygon();
265 0 : for (iFigure = FigureOffset(iShape); iFigure < iNextFigure; iFigure++)
266 : {
267 0 : OGRLinearRing* poRing = new OGRLinearRing();
268 0 : iPoint = PointOffset(iFigure);
269 0 : iNextPoint = NextPointOffset(iFigure);
270 0 : poRing->setNumPoints(iNextPoint - iPoint);
271 0 : i = 0;
272 0 : while (iPoint < iNextPoint)
273 : {
274 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
275 : {
276 0 : if ( chProps & SP_HASZVALUES )
277 0 : poRing->setPoint(i, ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
278 : else
279 0 : poRing->setPoint(i, ReadY(iPoint), ReadX(iPoint) );
280 : }
281 : else
282 : {
283 0 : if ( chProps & SP_HASZVALUES )
284 0 : poRing->setPoint(i, ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
285 : else
286 0 : poRing->setPoint(i, ReadX(iPoint), ReadY(iPoint) );
287 : }
288 :
289 0 : ++iPoint;
290 0 : ++i;
291 : }
292 0 : poPoly->addRingDirectly( poRing );
293 : }
294 0 : return poPoly;
295 : }
296 :
297 : /************************************************************************/
298 : /* ReadMultiPolygon() */
299 : /************************************************************************/
300 :
301 0 : OGRMultiPolygon* OGRMSSQLGeometryParser::ReadMultiPolygon(int iShape)
302 : {
303 : int i;
304 0 : OGRMultiPolygon* poMultiPolygon = new OGRMultiPolygon();
305 : OGRGeometry* poGeom;
306 :
307 0 : for (i = iShape + 1; i < nNumShapes; i++)
308 : {
309 0 : poGeom = NULL;
310 0 : if (ParentOffset(i) == (unsigned int)iShape)
311 : {
312 0 : if ( ShapeType(i) == ST_POLYGON )
313 0 : poGeom = ReadPolygon(i);
314 : }
315 0 : if ( poGeom )
316 0 : poMultiPolygon->addGeometryDirectly( poGeom );
317 : }
318 :
319 0 : return poMultiPolygon;
320 : }
321 :
322 : /************************************************************************/
323 : /* ReadGeometryCollection() */
324 : /************************************************************************/
325 :
326 0 : OGRGeometryCollection* OGRMSSQLGeometryParser::ReadGeometryCollection(int iShape)
327 : {
328 : int i;
329 0 : OGRGeometryCollection* poGeomColl = new OGRGeometryCollection();
330 : OGRGeometry* poGeom;
331 :
332 0 : for (i = iShape + 1; i < nNumShapes; i++)
333 : {
334 0 : poGeom = NULL;
335 0 : if (ParentOffset(i) == (unsigned int)iShape)
336 : {
337 0 : switch (ShapeType(i))
338 : {
339 : case ST_POINT:
340 0 : poGeom = ReadPoint(i);
341 0 : break;
342 : case ST_LINESTRING:
343 0 : poGeom = ReadLineString(i);
344 0 : break;
345 : case ST_POLYGON:
346 0 : poGeom = ReadPolygon(i);
347 0 : break;
348 : case ST_MULTIPOINT:
349 0 : poGeom = ReadMultiPoint(i);
350 0 : break;
351 : case ST_MULTILINESTRING:
352 0 : poGeom = ReadMultiLineString(i);
353 0 : break;
354 : case ST_MULTIPOLYGON:
355 0 : poGeom = ReadMultiPolygon(i);
356 0 : break;
357 : case ST_GEOMETRYCOLLECTION:
358 0 : poGeom = ReadGeometryCollection(i);
359 : break;
360 : }
361 : }
362 0 : if ( poGeom )
363 0 : poGeomColl->addGeometryDirectly( poGeom );
364 : }
365 :
366 0 : return poGeomColl;
367 : }
368 :
369 : /************************************************************************/
370 : /* ParseSqlGeometry() */
371 : /************************************************************************/
372 :
373 :
374 0 : OGRErr OGRMSSQLGeometryParser::ParseSqlGeometry(unsigned char* pszInput,
375 : int nLen, OGRGeometry **poGeom)
376 : {
377 0 : if (nLen < 10)
378 0 : return OGRERR_NOT_ENOUGH_DATA;
379 :
380 0 : pszData = pszInput;
381 :
382 : /* store the SRS id for further use */
383 0 : nSRSId = ReadInt32(0);
384 :
385 0 : if ( ReadByte(4) != 1 )
386 : {
387 0 : return OGRERR_CORRUPT_DATA;
388 : }
389 :
390 0 : chProps = ReadByte(5);
391 :
392 0 : if ( chProps & SP_HASMVALUES )
393 0 : nPointSize = 32;
394 0 : else if ( chProps & SP_HASZVALUES )
395 0 : nPointSize = 24;
396 : else
397 0 : nPointSize = 16;
398 :
399 0 : if ( chProps & SP_ISSINGLEPOINT )
400 : {
401 : // single point geometry
402 0 : nNumPoints = 1;
403 0 : nPointPos = 6;
404 :
405 0 : if (nLen < 6 + nPointSize)
406 : {
407 0 : return OGRERR_NOT_ENOUGH_DATA;
408 : }
409 :
410 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
411 : {
412 0 : if (chProps & SP_HASZVALUES)
413 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0), ReadZ(0));
414 : else
415 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0));
416 : }
417 : else
418 : {
419 0 : if (chProps & SP_HASZVALUES)
420 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0), ReadZ(0));
421 : else
422 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0));
423 : }
424 : }
425 0 : else if ( chProps & SP_ISSINGLELINESEGMENT )
426 : {
427 : // single line segment with 2 points
428 0 : nNumPoints = 2;
429 0 : nPointPos = 6;
430 :
431 0 : if (nLen < 6 + 2 * nPointSize)
432 : {
433 0 : return OGRERR_NOT_ENOUGH_DATA;
434 : }
435 :
436 0 : OGRLineString* line = new OGRLineString();
437 0 : line->setNumPoints(2);
438 :
439 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
440 : {
441 0 : if ( chProps & SP_HASZVALUES )
442 : {
443 0 : line->setPoint(0, ReadY(0), ReadX(0), ReadZ(0));
444 0 : line->setPoint(1, ReadY(1), ReadX(1), ReadZ(1));
445 : }
446 : else
447 : {
448 0 : line->setPoint(0, ReadY(0), ReadX(0));
449 0 : line->setPoint(1, ReadY(1), ReadX(1));
450 : }
451 : }
452 : else
453 : {
454 0 : if ( chProps & SP_HASZVALUES )
455 : {
456 0 : line->setPoint(0, ReadX(0), ReadY(0), ReadZ(0));
457 0 : line->setPoint(1, ReadX(1), ReadY(1), ReadZ(1));
458 : }
459 : else
460 : {
461 0 : line->setPoint(0, ReadX(0), ReadY(0));
462 0 : line->setPoint(1, ReadX(1), ReadY(1));
463 : }
464 : }
465 :
466 0 : *poGeom = line;
467 : }
468 : else
469 : {
470 : // complex geometries
471 0 : nNumPoints = ReadInt32(6);
472 :
473 0 : if ( nNumPoints <= 0 )
474 : {
475 0 : return OGRERR_NONE;
476 : }
477 :
478 : // position of the point array
479 0 : nPointPos = 10;
480 :
481 : // position of the figures
482 0 : nFigurePos = nPointPos + nPointSize * nNumPoints + 4;
483 :
484 0 : if (nLen < nFigurePos)
485 : {
486 0 : return OGRERR_NOT_ENOUGH_DATA;
487 : }
488 :
489 0 : nNumFigures = ReadInt32(nFigurePos - 4);
490 :
491 0 : if ( nNumFigures <= 0 )
492 : {
493 0 : return OGRERR_NONE;
494 : }
495 :
496 : // position of the shapes
497 0 : nShapePos = nFigurePos + 5 * nNumFigures + 4;
498 :
499 0 : if (nLen < nShapePos)
500 : {
501 0 : return OGRERR_NOT_ENOUGH_DATA;
502 : }
503 :
504 0 : nNumShapes = ReadInt32(nShapePos - 4);
505 :
506 0 : if (nLen < nShapePos + 9 * nNumShapes)
507 : {
508 0 : return OGRERR_NOT_ENOUGH_DATA;
509 : }
510 :
511 0 : if ( nNumShapes <= 0 )
512 : {
513 0 : return OGRERR_NONE;
514 : }
515 :
516 : // pick up the root shape
517 0 : if ( ParentOffset(0) != 0xFFFFFFFF)
518 : {
519 0 : return OGRERR_CORRUPT_DATA;
520 : }
521 :
522 : // determine the shape type
523 0 : switch (ShapeType(0))
524 : {
525 : case ST_POINT:
526 0 : *poGeom = ReadPoint(0);
527 0 : break;
528 : case ST_LINESTRING:
529 0 : *poGeom = ReadLineString(0);
530 0 : break;
531 : case ST_POLYGON:
532 0 : *poGeom = ReadPolygon(0);
533 0 : break;
534 : case ST_MULTIPOINT:
535 0 : *poGeom = ReadMultiPoint(0);
536 0 : break;
537 : case ST_MULTILINESTRING:
538 0 : *poGeom = ReadMultiLineString(0);
539 0 : break;
540 : case ST_MULTIPOLYGON:
541 0 : *poGeom = ReadMultiPolygon(0);
542 0 : break;
543 : case ST_GEOMETRYCOLLECTION:
544 0 : *poGeom = ReadGeometryCollection(0);
545 0 : break;
546 : default:
547 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
548 : }
549 : }
550 :
551 0 : return OGRERR_NONE;
552 : }
553 :
|