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