Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: MSSQL Spatial driver
4 : * Purpose: Implements OGRMSSQLGeometryParser class to parse native
5 : *SqlGeometries. Author: Tamas Szekeres, szekerest at gmail.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Tamas Szekeres
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_conv.h"
14 : #include "ogr_mssqlspatial.h"
15 :
16 : /* SqlGeometry/SqlGeography serialization format
17 :
18 : Simple Point (SerializationProps & IsSinglePoint)
19 : [SRID][0x01][SerializationProps][Point][z][m]
20 :
21 : Simple Line Segment (SerializationProps & IsSingleLineSegment)
22 : [SRID][0x01][SerializationProps][Point1][Point2][z1][z2][m1][m2]
23 :
24 : Complex Geometries
25 : [SRID][VersionAttribute][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN]
26 : [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape]
27 :
28 : Complex Geometries (FigureAttribute == Curve)
29 : [SRID][VersionAttribute][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN]
30 : [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape][NumSegments][SegmentType]..[SegmentType]
31 :
32 : VersionAttribute (1 byte)
33 : 0x01 = Katmai (MSSQL2008+)
34 : 0x02 = Denali (MSSQL2012+)
35 :
36 : SRID
37 : Spatial Reference Id (4 bytes)
38 :
39 : SerializationProps (bitmask) 1 byte
40 : 0x01 = HasZValues
41 : 0x02 = HasMValues
42 : 0x04 = IsValid
43 : 0x08 = IsSinglePoint
44 : 0x10 = IsSingleLineSegment
45 : 0x20 = IsLargerThanAHemisphere
46 :
47 : Point (2-4)x8 bytes, size depends on SerializationProps & HasZValues &
48 : HasMValues [x][y] - SqlGeometry [latitude][longitude] -
49 : SqlGeography
50 :
51 : Figure
52 : [FigureAttribute][PointOffset]
53 :
54 : FigureAttribute - Katmai (1 byte)
55 : 0x00 = Interior Ring
56 : 0x01 = Stroke
57 : 0x02 = Exterior Ring
58 :
59 : FigureAttribute - Denali (1 byte)
60 : 0x00 = None
61 : 0x01 = Line
62 : 0x02 = Arc
63 : 0x03 = Curve
64 :
65 : Shape
66 : [ParentFigureOffset][FigureOffset][ShapeType]
67 :
68 : ShapeType (1 byte)
69 : 0x00 = Unknown
70 : 0x01 = Point
71 : 0x02 = LineString
72 : 0x03 = Polygon
73 : 0x04 = MultiPoint
74 : 0x05 = MultiLineString
75 : 0x06 = MultiPolygon
76 : 0x07 = GeometryCollection
77 : -- Denali
78 : 0x08 = CircularString
79 : 0x09 = CompoundCurve
80 : 0x0A = CurvePolygon
81 : 0x0B = FullGlobe
82 :
83 : SegmentType (1 byte)
84 : 0x00 = Line
85 : 0x01 = Arc
86 : 0x02 = FirstLine
87 : 0x03 = FirstArc
88 :
89 : */
90 :
91 : /************************************************************************/
92 : /* Geometry parser macros */
93 : /************************************************************************/
94 :
95 : #define ReadInt32(nPos) (*((int *)(pszData + (nPos))))
96 :
97 : #define ReadByte(nPos) (pszData[nPos])
98 :
99 : #define ReadDouble(nPos) (*((double *)(pszData + (nPos))))
100 :
101 : #define ParentOffset(iShape) (ReadInt32(nShapePos + (iShape)*9))
102 : #define FigureOffset(iShape) (ReadInt32(nShapePos + (iShape)*9 + 4))
103 : #define ShapeType(iShape) (ReadByte(nShapePos + (iShape)*9 + 8))
104 : #define SegmentType(iSegment) (ReadByte(nSegmentPos + (iSegment)))
105 :
106 : #define FigureAttribute(iFigure) (ReadByte(nFigurePos + (iFigure)*5))
107 : #define PointOffset(iFigure) (ReadInt32(nFigurePos + (iFigure)*5 + 1))
108 : #define NextPointOffset(iFigure) \
109 : (iFigure + 1 < nNumFigures ? PointOffset((iFigure) + 1) : nNumPoints)
110 :
111 : #define ReadX(iPoint) (ReadDouble(nPointPos + 16 * (iPoint)))
112 : #define ReadY(iPoint) (ReadDouble(nPointPos + 16 * (iPoint) + 8))
113 : #define ReadZ(iPoint) (ReadDouble(nPointPos + 16 * nNumPoints + 8 * (iPoint)))
114 : #define ReadM(iPoint) (ReadDouble(nPointPos + 24 * nNumPoints + 8 * (iPoint)))
115 :
116 : /************************************************************************/
117 : /* OGRMSSQLGeometryParser() */
118 : /************************************************************************/
119 :
120 0 : OGRMSSQLGeometryParser::OGRMSSQLGeometryParser(int nGeomColumnType)
121 : {
122 0 : nColType = nGeomColumnType;
123 0 : pszData = nullptr;
124 0 : chProps = 0;
125 0 : nPointSize = 0;
126 0 : nPointPos = 0;
127 0 : nNumPoints = 0;
128 0 : nFigurePos = 0;
129 0 : nNumFigures = 0;
130 0 : nShapePos = 0;
131 0 : nNumShapes = 0;
132 0 : nSegmentPos = 0;
133 0 : nNumSegments = 0;
134 0 : nSRSId = 0;
135 0 : chVersion = 0;
136 0 : iSegment = 0;
137 0 : }
138 :
139 : /************************************************************************/
140 : /* ReadPoint() */
141 : /************************************************************************/
142 :
143 0 : OGRPoint *OGRMSSQLGeometryParser::ReadPoint(int iFigure)
144 : {
145 0 : if (iFigure == -1)
146 : {
147 : /* creating an empty point */
148 0 : OGRPoint *poPoint = new OGRPoint();
149 0 : if (chProps & SP_HASZVALUES)
150 0 : poPoint->setCoordinateDimension(3);
151 :
152 0 : if (chProps & SP_HASMVALUES)
153 0 : poPoint->setMeasured(TRUE);
154 :
155 0 : return poPoint;
156 : }
157 :
158 0 : if (iFigure < nNumFigures)
159 : {
160 0 : int iPoint = PointOffset(iFigure);
161 0 : if (iPoint < nNumPoints)
162 : {
163 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
164 : {
165 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
166 0 : return new OGRPoint(ReadY(iPoint), ReadX(iPoint),
167 0 : ReadZ(iPoint), ReadM(iPoint));
168 0 : else if (chProps & SP_HASZVALUES)
169 0 : return new OGRPoint(ReadY(iPoint), ReadX(iPoint),
170 0 : ReadZ(iPoint));
171 0 : else if (chProps & SP_HASMVALUES)
172 : {
173 : OGRPoint *poPoint =
174 0 : new OGRPoint(ReadY(iPoint), ReadX(iPoint));
175 0 : poPoint->setM(ReadZ(iPoint));
176 0 : return poPoint;
177 : }
178 : else
179 0 : return new OGRPoint(ReadY(iPoint), ReadX(iPoint));
180 : }
181 : else
182 : {
183 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
184 0 : return new OGRPoint(ReadX(iPoint), ReadY(iPoint),
185 0 : ReadZ(iPoint), ReadM(iPoint));
186 0 : else if (chProps & SP_HASZVALUES)
187 0 : return new OGRPoint(ReadX(iPoint), ReadY(iPoint),
188 0 : ReadZ(iPoint));
189 0 : else if (chProps & SP_HASMVALUES)
190 : {
191 : OGRPoint *poPoint =
192 0 : new OGRPoint(ReadX(iPoint), ReadY(iPoint));
193 0 : poPoint->setM(ReadZ(iPoint));
194 0 : return poPoint;
195 : }
196 : else
197 0 : return new OGRPoint(ReadX(iPoint), ReadY(iPoint));
198 : }
199 : }
200 : }
201 0 : return nullptr;
202 : }
203 :
204 : /************************************************************************/
205 : /* ReadMultiPoint() */
206 : /************************************************************************/
207 :
208 0 : OGRMultiPoint *OGRMSSQLGeometryParser::ReadMultiPoint(int iShape)
209 : {
210 0 : OGRMultiPoint *poMultiPoint = new OGRMultiPoint();
211 : OGRGeometry *poGeom;
212 :
213 0 : for (int i = iShape + 1; i < nNumShapes; i++)
214 : {
215 0 : poGeom = nullptr;
216 0 : if (ParentOffset(i) == iShape)
217 : {
218 0 : if (ShapeType(i) == ST_POINT)
219 0 : poGeom = ReadPoint(FigureOffset(i));
220 : }
221 0 : if (poGeom)
222 0 : poMultiPoint->addGeometryDirectly(poGeom);
223 : }
224 :
225 0 : return poMultiPoint;
226 : }
227 :
228 : /************************************************************************/
229 : /* ReadSimpleCurve() */
230 : /************************************************************************/
231 :
232 0 : OGRErr OGRMSSQLGeometryParser::ReadSimpleCurve(OGRSimpleCurve *poCurve,
233 : int iPoint, int iNextPoint)
234 : {
235 0 : if (iPoint >= iNextPoint)
236 0 : return OGRERR_NOT_ENOUGH_DATA;
237 :
238 0 : poCurve->setNumPoints(iNextPoint - iPoint);
239 0 : int i = 0;
240 0 : while (iPoint < iNextPoint)
241 : {
242 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
243 : {
244 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
245 0 : poCurve->setPoint(i, ReadY(iPoint), ReadX(iPoint),
246 0 : ReadZ(iPoint), ReadM(iPoint));
247 0 : else if (chProps & SP_HASZVALUES)
248 0 : poCurve->setPoint(i, ReadY(iPoint), ReadX(iPoint),
249 0 : ReadZ(iPoint));
250 0 : else if (chProps & SP_HASMVALUES)
251 0 : poCurve->setPointM(i, ReadY(iPoint), ReadX(iPoint),
252 0 : ReadZ(iPoint));
253 : else
254 0 : poCurve->setPoint(i, ReadY(iPoint), ReadX(iPoint));
255 : }
256 : else
257 : {
258 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
259 0 : poCurve->setPoint(i, ReadX(iPoint), ReadY(iPoint),
260 0 : ReadZ(iPoint), ReadM(iPoint));
261 0 : else if (chProps & SP_HASZVALUES)
262 0 : poCurve->setPoint(i, ReadX(iPoint), ReadY(iPoint),
263 0 : ReadZ(iPoint));
264 0 : else if (chProps & SP_HASMVALUES)
265 0 : poCurve->setPointM(i, ReadX(iPoint), ReadY(iPoint),
266 0 : ReadZ(iPoint));
267 : else
268 0 : poCurve->setPoint(i, ReadX(iPoint), ReadY(iPoint));
269 : }
270 :
271 0 : ++iPoint;
272 0 : ++i;
273 : }
274 :
275 0 : return OGRERR_NONE;
276 : }
277 :
278 : /************************************************************************/
279 : /* ReadLineString() */
280 : /************************************************************************/
281 :
282 0 : OGRLineString *OGRMSSQLGeometryParser::ReadLineString(int iFigure)
283 : {
284 0 : OGRLineString *poLineString = new OGRLineString();
285 0 : if (iFigure == -1)
286 : {
287 0 : if (chProps & SP_HASZVALUES)
288 0 : poLineString->setCoordinateDimension(3);
289 :
290 0 : if (chProps & SP_HASMVALUES)
291 0 : poLineString->setMeasured(TRUE);
292 : }
293 : else
294 0 : ReadSimpleCurve(poLineString, PointOffset(iFigure),
295 0 : NextPointOffset(iFigure));
296 :
297 0 : return poLineString;
298 : }
299 :
300 : /************************************************************************/
301 : /* ReadLinearRing() */
302 : /************************************************************************/
303 :
304 0 : OGRLinearRing *OGRMSSQLGeometryParser::ReadLinearRing(int iFigure)
305 : {
306 0 : OGRLinearRing *poLinearRing = new OGRLinearRing();
307 0 : ReadSimpleCurve(poLinearRing, PointOffset(iFigure),
308 0 : NextPointOffset(iFigure));
309 0 : return poLinearRing;
310 : }
311 :
312 : /************************************************************************/
313 : /* ReadCircularString() */
314 : /************************************************************************/
315 :
316 0 : OGRCircularString *OGRMSSQLGeometryParser::ReadCircularString(int iFigure)
317 : {
318 0 : OGRCircularString *poCircularString = new OGRCircularString();
319 0 : if (iFigure == -1)
320 : {
321 0 : if (chProps & SP_HASZVALUES)
322 0 : poCircularString->setCoordinateDimension(3);
323 :
324 0 : if (chProps & SP_HASMVALUES)
325 0 : poCircularString->setMeasured(TRUE);
326 : }
327 : else
328 0 : ReadSimpleCurve(poCircularString, PointOffset(iFigure),
329 0 : NextPointOffset(iFigure));
330 :
331 0 : return poCircularString;
332 : }
333 :
334 : /************************************************************************/
335 : /* ReadMultiLineString() */
336 : /************************************************************************/
337 :
338 0 : OGRMultiLineString *OGRMSSQLGeometryParser::ReadMultiLineString(int iShape)
339 : {
340 0 : OGRMultiLineString *poMultiLineString = new OGRMultiLineString();
341 : OGRGeometry *poGeom;
342 :
343 0 : for (int i = iShape + 1; i < nNumShapes; i++)
344 : {
345 0 : poGeom = nullptr;
346 0 : if (ParentOffset(i) == iShape)
347 : {
348 0 : if (ShapeType(i) == ST_LINESTRING)
349 0 : poGeom = ReadLineString(FigureOffset(i));
350 : }
351 0 : if (poGeom)
352 0 : poMultiLineString->addGeometryDirectly(poGeom);
353 : }
354 :
355 0 : return poMultiLineString;
356 : }
357 :
358 : /************************************************************************/
359 : /* ReadPolygon() */
360 : /************************************************************************/
361 :
362 0 : OGRPolygon *OGRMSSQLGeometryParser::ReadPolygon(int iShape)
363 : {
364 : int iFigure, iNextFigure;
365 :
366 0 : OGRPolygon *poPoly = new OGRPolygon();
367 :
368 0 : if ((iFigure = FigureOffset(iShape)) == -1)
369 0 : return poPoly;
370 :
371 : /* find next shape that has a figure */
372 0 : iNextFigure = -1;
373 0 : while (++iShape < nNumShapes)
374 : {
375 0 : if ((iNextFigure = FigureOffset(iShape)) != -1)
376 0 : break;
377 : }
378 0 : if (iNextFigure == -1)
379 0 : iNextFigure = nNumFigures;
380 :
381 0 : while (iFigure < iNextFigure)
382 : {
383 0 : poPoly->addRingDirectly(ReadLinearRing(iFigure));
384 0 : ++iFigure;
385 : }
386 :
387 0 : poPoly->closeRings();
388 0 : return poPoly;
389 : }
390 :
391 : /************************************************************************/
392 : /* ReadMultiPolygon() */
393 : /************************************************************************/
394 :
395 0 : OGRMultiPolygon *OGRMSSQLGeometryParser::ReadMultiPolygon(int iShape)
396 : {
397 0 : OGRMultiPolygon *poMultiPolygon = new OGRMultiPolygon();
398 : OGRGeometry *poGeom;
399 :
400 0 : for (int i = iShape + 1; i < nNumShapes; i++)
401 : {
402 0 : poGeom = nullptr;
403 0 : if (ParentOffset(i) == iShape)
404 : {
405 0 : if (ShapeType(i) == ST_POLYGON)
406 0 : poGeom = ReadPolygon(i);
407 : }
408 0 : if (poGeom)
409 0 : poMultiPolygon->addGeometryDirectly(poGeom);
410 : }
411 :
412 0 : return poMultiPolygon;
413 : }
414 :
415 : /************************************************************************/
416 : /* AddCurveSegment() */
417 : /************************************************************************/
418 :
419 0 : void OGRMSSQLGeometryParser::AddCurveSegment(OGRCompoundCurve *poCompoundCurve,
420 : OGRSimpleCurve *poCurve,
421 : int iPoint, int iNextPoint)
422 : {
423 0 : if (poCurve != nullptr)
424 : {
425 0 : if (iPoint < iNextPoint)
426 : {
427 0 : ReadSimpleCurve(poCurve, iPoint, iNextPoint);
428 0 : poCompoundCurve->addCurveDirectly(poCurve);
429 : }
430 : else
431 0 : delete poCurve;
432 : }
433 0 : }
434 :
435 : /************************************************************************/
436 : /* ReadCompoundCurve() */
437 : /************************************************************************/
438 :
439 0 : OGRCompoundCurve *OGRMSSQLGeometryParser::ReadCompoundCurve(int iFigure)
440 : {
441 : int iPoint, iNextPoint, nPointsPrepared;
442 0 : OGRCompoundCurve *poCompoundCurve = new OGRCompoundCurve();
443 :
444 0 : if (iFigure == -1)
445 : {
446 0 : if (chProps & SP_HASZVALUES)
447 0 : poCompoundCurve->setCoordinateDimension(3);
448 :
449 0 : if (chProps & SP_HASMVALUES)
450 0 : poCompoundCurve->setMeasured(TRUE);
451 :
452 0 : return poCompoundCurve;
453 : }
454 :
455 0 : iPoint = PointOffset(iFigure);
456 0 : iNextPoint = NextPointOffset(iFigure) - 1;
457 :
458 0 : OGRSimpleCurve *poCurve = nullptr;
459 :
460 0 : nPointsPrepared = 0;
461 0 : while (iPoint < iNextPoint && iSegment < nNumSegments)
462 : {
463 0 : switch (SegmentType(iSegment))
464 : {
465 0 : case SMT_FIRSTLINE:
466 0 : AddCurveSegment(poCompoundCurve, poCurve,
467 : iPoint - nPointsPrepared, iPoint + 1);
468 0 : poCurve = new OGRLineString();
469 0 : nPointsPrepared = 1;
470 0 : ++iPoint;
471 0 : break;
472 0 : case SMT_LINE:
473 0 : ++nPointsPrepared;
474 0 : ++iPoint;
475 0 : break;
476 0 : case SMT_FIRSTARC:
477 0 : AddCurveSegment(poCompoundCurve, poCurve,
478 : iPoint - nPointsPrepared, iPoint + 1);
479 0 : poCurve = new OGRCircularString();
480 0 : nPointsPrepared = 2;
481 0 : iPoint += 2;
482 0 : break;
483 0 : case SMT_ARC:
484 0 : nPointsPrepared += 2;
485 0 : iPoint += 2;
486 0 : break;
487 : }
488 0 : ++iSegment;
489 : }
490 :
491 : // adding the last curve
492 0 : if (iPoint == iNextPoint)
493 0 : AddCurveSegment(poCompoundCurve, poCurve, iPoint - nPointsPrepared,
494 : iPoint + 1);
495 : else
496 0 : delete poCurve;
497 :
498 0 : return poCompoundCurve;
499 : }
500 :
501 : /************************************************************************/
502 : /* ReadCurvePolygon() */
503 : /************************************************************************/
504 :
505 0 : OGRCurvePolygon *OGRMSSQLGeometryParser::ReadCurvePolygon(int iShape)
506 : {
507 : int iFigure, iNextFigure;
508 :
509 0 : OGRCurvePolygon *poPoly = new OGRCurvePolygon();
510 :
511 0 : if ((iFigure = FigureOffset(iShape)) == -1)
512 0 : return poPoly;
513 :
514 : /* find next shape that has a figure */
515 0 : iNextFigure = -1;
516 0 : while (++iShape < nNumShapes)
517 : {
518 0 : if ((iNextFigure = FigureOffset(iShape)) != -1)
519 0 : break;
520 : }
521 0 : if (iNextFigure == -1)
522 0 : iNextFigure = nNumFigures;
523 :
524 0 : while (iFigure < iNextFigure)
525 : {
526 0 : switch (FigureAttribute(iFigure))
527 : {
528 0 : case FA_LINE:
529 0 : poPoly->addRingDirectly(ReadLineString(iFigure));
530 0 : break;
531 0 : case FA_ARC:
532 0 : poPoly->addRingDirectly(ReadCircularString(iFigure));
533 0 : break;
534 0 : case FA_CURVE:
535 0 : poPoly->addRingDirectly(ReadCompoundCurve(iFigure));
536 0 : break;
537 : }
538 0 : ++iFigure;
539 : }
540 0 : poPoly->closeRings();
541 0 : return poPoly;
542 : }
543 :
544 : /************************************************************************/
545 : /* ReadGeometryCollection() */
546 : /************************************************************************/
547 :
548 : OGRGeometryCollection *
549 0 : OGRMSSQLGeometryParser::ReadGeometryCollection(int iShape)
550 : {
551 0 : OGRGeometryCollection *poGeomColl = new OGRGeometryCollection();
552 : OGRGeometry *poGeom;
553 :
554 0 : for (int i = iShape + 1; i < nNumShapes; i++)
555 : {
556 0 : poGeom = nullptr;
557 0 : if (ParentOffset(i) == iShape)
558 : {
559 0 : switch (ShapeType(i))
560 : {
561 0 : case ST_POINT:
562 0 : poGeom = ReadPoint(FigureOffset(i));
563 0 : break;
564 0 : case ST_LINESTRING:
565 0 : poGeom = ReadLineString(FigureOffset(i));
566 0 : break;
567 0 : case ST_POLYGON:
568 0 : poGeom = ReadPolygon(i);
569 0 : break;
570 0 : case ST_MULTIPOINT:
571 0 : poGeom = ReadMultiPoint(i);
572 0 : break;
573 0 : case ST_MULTILINESTRING:
574 0 : poGeom = ReadMultiLineString(i);
575 0 : break;
576 0 : case ST_MULTIPOLYGON:
577 0 : poGeom = ReadMultiPolygon(i);
578 0 : break;
579 0 : case ST_GEOMETRYCOLLECTION:
580 0 : poGeom = ReadGeometryCollection(i);
581 0 : break;
582 0 : case ST_CIRCULARSTRING:
583 0 : poGeom = ReadCircularString(FigureOffset(i));
584 0 : break;
585 0 : case ST_COMPOUNDCURVE:
586 0 : poGeom = ReadCompoundCurve(FigureOffset(i));
587 0 : break;
588 0 : case ST_CURVEPOLYGON:
589 0 : poGeom = ReadCurvePolygon(i);
590 0 : break;
591 : }
592 : }
593 0 : if (poGeom)
594 0 : poGeomColl->addGeometryDirectly(poGeom);
595 : }
596 :
597 0 : return poGeomColl;
598 : }
599 :
600 : /************************************************************************/
601 : /* ParseSqlGeometry() */
602 : /************************************************************************/
603 :
604 0 : OGRErr OGRMSSQLGeometryParser::ParseSqlGeometry(unsigned char *pszInput,
605 : int nLen, OGRGeometry **poGeom)
606 : {
607 0 : if (nLen < 10)
608 0 : return OGRERR_NOT_ENOUGH_DATA;
609 :
610 0 : pszData = pszInput;
611 :
612 : /* store the SRS id for further use */
613 0 : nSRSId = ReadInt32(0);
614 :
615 0 : chVersion = ReadByte(4);
616 :
617 0 : if (chVersion == 0 || chVersion > 2)
618 : {
619 0 : return OGRERR_CORRUPT_DATA;
620 : }
621 :
622 0 : chProps = ReadByte(5);
623 :
624 0 : nPointSize = 16;
625 :
626 0 : if (chProps & SP_HASZVALUES)
627 0 : nPointSize += 8;
628 :
629 0 : if (chProps & SP_HASMVALUES)
630 0 : nPointSize += 8;
631 :
632 0 : if (chProps & SP_ISSINGLEPOINT)
633 : {
634 : // single point geometry
635 0 : nNumPoints = 1;
636 0 : nPointPos = 6;
637 :
638 0 : if (nLen < 6 + nPointSize)
639 : {
640 0 : return OGRERR_NOT_ENOUGH_DATA;
641 : }
642 :
643 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
644 : {
645 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
646 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0), ReadZ(0), ReadM(0));
647 0 : else if (chProps & SP_HASZVALUES)
648 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0), ReadZ(0));
649 0 : else if (chProps & SP_HASMVALUES)
650 : {
651 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0));
652 0 : ((OGRPoint *)(*poGeom))->setM(ReadZ(0));
653 : }
654 : else
655 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0));
656 : }
657 : else
658 : {
659 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
660 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0), ReadZ(0), ReadM(0));
661 0 : else if (chProps & SP_HASZVALUES)
662 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0), ReadZ(0));
663 0 : else if (chProps & SP_HASMVALUES)
664 : {
665 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0));
666 0 : ((OGRPoint *)(*poGeom))->setM(ReadZ(0));
667 : }
668 : else
669 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0));
670 : }
671 : }
672 0 : else if (chProps & SP_ISSINGLELINESEGMENT)
673 : {
674 : // single line segment with 2 points
675 0 : nNumPoints = 2;
676 0 : nPointPos = 6;
677 :
678 0 : if (nLen < 6 + 2 * nPointSize)
679 : {
680 0 : return OGRERR_NOT_ENOUGH_DATA;
681 : }
682 :
683 0 : OGRLineString *line = new OGRLineString();
684 0 : line->setNumPoints(2);
685 :
686 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
687 : {
688 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
689 : {
690 0 : line->setPoint(0, ReadY(0), ReadX(0), ReadZ(0), ReadM(0));
691 0 : line->setPoint(1, ReadY(1), ReadX(1), ReadZ(1), ReadM(1));
692 : }
693 0 : else if (chProps & SP_HASZVALUES)
694 : {
695 0 : line->setPoint(0, ReadY(0), ReadX(0), ReadZ(0));
696 0 : line->setPoint(1, ReadY(1), ReadX(1), ReadZ(1));
697 : }
698 0 : else if (chProps & SP_HASMVALUES)
699 : {
700 0 : line->setPointM(0, ReadY(0), ReadX(0), ReadZ(0));
701 0 : line->setPointM(1, ReadY(1), ReadX(1), ReadZ(1));
702 : }
703 : else
704 : {
705 0 : line->setPoint(0, ReadY(0), ReadX(0));
706 0 : line->setPoint(1, ReadY(1), ReadX(1));
707 : }
708 : }
709 : else
710 : {
711 0 : if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
712 : {
713 0 : line->setPoint(0, ReadX(0), ReadY(0), ReadZ(0), ReadM(0));
714 0 : line->setPoint(1, ReadX(1), ReadY(1), ReadZ(1), ReadM(1));
715 : }
716 0 : else if (chProps & SP_HASZVALUES)
717 : {
718 0 : line->setPoint(0, ReadX(0), ReadY(0), ReadZ(0));
719 0 : line->setPoint(1, ReadX(1), ReadY(1), ReadZ(1));
720 : }
721 0 : else if (chProps & SP_HASMVALUES)
722 : {
723 0 : line->setPointM(0, ReadX(0), ReadY(0), ReadZ(0));
724 0 : line->setPointM(1, ReadX(1), ReadY(1), ReadZ(1));
725 : }
726 : else
727 : {
728 0 : line->setPoint(0, ReadX(0), ReadY(0));
729 0 : line->setPoint(1, ReadX(1), ReadY(1));
730 : }
731 : }
732 :
733 0 : *poGeom = line;
734 : }
735 : else
736 : {
737 : // complex geometries
738 0 : nNumPoints = ReadInt32(6);
739 :
740 0 : if (nNumPoints < 0)
741 : {
742 0 : return OGRERR_NONE;
743 : }
744 :
745 : // position of the point array
746 0 : nPointPos = 10;
747 :
748 : // position of the figures
749 0 : nFigurePos = nPointPos + nPointSize * nNumPoints + 4;
750 :
751 0 : if (nLen < nFigurePos)
752 : {
753 0 : return OGRERR_NOT_ENOUGH_DATA;
754 : }
755 :
756 0 : nNumFigures = ReadInt32(nFigurePos - 4);
757 :
758 0 : if (nNumFigures < 0)
759 : {
760 0 : return OGRERR_NONE;
761 : }
762 :
763 : // position of the shapes
764 0 : nShapePos = nFigurePos + 5 * nNumFigures + 4;
765 :
766 0 : if (nLen < nShapePos)
767 : {
768 0 : return OGRERR_NOT_ENOUGH_DATA;
769 : }
770 :
771 0 : nNumShapes = ReadInt32(nShapePos - 4);
772 :
773 0 : if (nLen < nShapePos + 9 * nNumShapes)
774 : {
775 0 : return OGRERR_NOT_ENOUGH_DATA;
776 : }
777 :
778 0 : if (nNumShapes <= 0)
779 : {
780 0 : return OGRERR_NONE;
781 : }
782 :
783 : // position of the segments (for complex curve figures)
784 0 : if (chVersion == 0x02)
785 : {
786 0 : iSegment = 0;
787 0 : nSegmentPos = nShapePos + 9 * nNumShapes + 4;
788 0 : if (nLen > nSegmentPos)
789 : {
790 : // segment array is present
791 0 : nNumSegments = ReadInt32(nSegmentPos - 4);
792 0 : if (nLen < nSegmentPos + nNumSegments)
793 : {
794 0 : return OGRERR_NOT_ENOUGH_DATA;
795 : }
796 : }
797 : }
798 :
799 : // pick up the root shape
800 0 : if (ParentOffset(0) != -1)
801 : {
802 0 : return OGRERR_CORRUPT_DATA;
803 : }
804 :
805 : // determine the shape type
806 0 : switch (ShapeType(0))
807 : {
808 0 : case ST_POINT:
809 0 : *poGeom = ReadPoint(FigureOffset(0));
810 0 : break;
811 0 : case ST_LINESTRING:
812 0 : *poGeom = ReadLineString(FigureOffset(0));
813 0 : break;
814 0 : case ST_POLYGON:
815 0 : *poGeom = ReadPolygon(0);
816 0 : break;
817 0 : case ST_MULTIPOINT:
818 0 : *poGeom = ReadMultiPoint(0);
819 0 : break;
820 0 : case ST_MULTILINESTRING:
821 0 : *poGeom = ReadMultiLineString(0);
822 0 : break;
823 0 : case ST_MULTIPOLYGON:
824 0 : *poGeom = ReadMultiPolygon(0);
825 0 : break;
826 0 : case ST_GEOMETRYCOLLECTION:
827 0 : *poGeom = ReadGeometryCollection(0);
828 0 : break;
829 0 : case ST_CIRCULARSTRING:
830 0 : *poGeom = ReadCircularString(FigureOffset(0));
831 0 : break;
832 0 : case ST_COMPOUNDCURVE:
833 0 : *poGeom = ReadCompoundCurve(FigureOffset(0));
834 0 : break;
835 0 : case ST_CURVEPOLYGON:
836 0 : *poGeom = ReadCurvePolygon(0);
837 0 : break;
838 0 : default:
839 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
840 : }
841 : }
842 :
843 0 : return OGRERR_NONE;
844 : }
845 :
846 : #undef ParentOffset
847 : #undef FigureOffset
848 : #undef ShapeType
849 : #undef SegmentType
850 :
851 : #undef FigureAttribute
852 : #undef PointOffset
853 : #undef NextPointOffset
|