1 : /******************************************************************************
2 : * $Id: ogrmssqlgeometryparser.cpp 24330 2012-04-28 11:46:49Z 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 24330 2012-04-28 11:46:49Z 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(int nGeomColumnType)
81 : {
82 0 : nColType = nGeomColumnType;
83 0 : }
84 :
85 : /************************************************************************/
86 : /* ReadPoint() */
87 : /************************************************************************/
88 :
89 0 : OGRPoint* OGRMSSQLGeometryParser::ReadPoint(int iShape)
90 : {
91 0 : int iFigure = FigureOffset(iShape);
92 0 : if ( iFigure < nNumFigures )
93 : {
94 0 : int iPoint = PointOffset(iFigure);
95 0 : if ( iPoint < nNumPoints )
96 : {
97 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
98 : {
99 0 : if ( chProps & SP_HASZVALUES )
100 0 : return new OGRPoint( ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
101 : else
102 0 : return new OGRPoint( ReadY(iPoint), ReadX(iPoint) );
103 : }
104 : else
105 : {
106 0 : if ( chProps & SP_HASZVALUES )
107 0 : return new OGRPoint( ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
108 : else
109 0 : return new OGRPoint( ReadX(iPoint), ReadY(iPoint) );
110 : }
111 : }
112 : }
113 0 : return NULL;
114 : }
115 :
116 : /************************************************************************/
117 : /* ReadMultiPoint() */
118 : /************************************************************************/
119 :
120 0 : OGRMultiPoint* OGRMSSQLGeometryParser::ReadMultiPoint(int iShape)
121 : {
122 : int iFigure, iPoint, iNextPoint;
123 0 : iFigure = FigureOffset(iShape);
124 :
125 0 : OGRMultiPoint* poMultiPoint = new OGRMultiPoint();
126 0 : iNextPoint = NextPointOffset(iFigure);
127 0 : for (iPoint = PointOffset(iFigure); iPoint < iNextPoint; iPoint++)
128 : {
129 : OGRPoint* poPoint;
130 :
131 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
132 : {
133 0 : if ( chProps & SP_HASZVALUES )
134 0 : poPoint = new OGRPoint( ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
135 : else
136 0 : poPoint = new OGRPoint( ReadY(iPoint), ReadX(iPoint) );
137 : }
138 : else
139 : {
140 0 : if ( chProps & SP_HASZVALUES )
141 0 : poPoint = new OGRPoint( ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
142 : else
143 0 : poPoint = new OGRPoint( ReadX(iPoint), ReadY(iPoint) );
144 : }
145 :
146 0 : if ( poPoint )
147 0 : poMultiPoint->addGeometryDirectly( poPoint );
148 : }
149 :
150 0 : return poMultiPoint;
151 : }
152 :
153 : /************************************************************************/
154 : /* ReadLineString() */
155 : /************************************************************************/
156 :
157 0 : OGRLineString* OGRMSSQLGeometryParser::ReadLineString(int iShape)
158 : {
159 : int iFigure, iPoint, iNextPoint, i;
160 0 : iFigure = FigureOffset(iShape);
161 :
162 0 : OGRLineString* poLineString = new OGRLineString();
163 0 : iPoint = PointOffset(iFigure);
164 0 : iNextPoint = NextPointOffset(iFigure);
165 0 : poLineString->setNumPoints(iNextPoint - iPoint);
166 0 : i = 0;
167 0 : while (iPoint < iNextPoint)
168 : {
169 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
170 : {
171 0 : if ( chProps & SP_HASZVALUES )
172 0 : poLineString->setPoint(i, ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
173 : else
174 0 : poLineString->setPoint(i, ReadY(iPoint), ReadX(iPoint) );
175 : }
176 : else
177 : {
178 0 : if ( chProps & SP_HASZVALUES )
179 0 : poLineString->setPoint(i, ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
180 : else
181 0 : poLineString->setPoint(i, ReadX(iPoint), ReadY(iPoint) );
182 : }
183 :
184 0 : ++iPoint;
185 0 : ++i;
186 : }
187 :
188 0 : return poLineString;
189 : }
190 :
191 : /************************************************************************/
192 : /* ReadMultiLineString() */
193 : /************************************************************************/
194 :
195 0 : OGRMultiLineString* OGRMSSQLGeometryParser::ReadMultiLineString(int iShape)
196 : {
197 : int i;
198 0 : OGRMultiLineString* poMultiLineString = new OGRMultiLineString();
199 : OGRGeometry* poGeom;
200 :
201 0 : for (i = iShape + 1; i < nNumShapes; i++)
202 : {
203 0 : poGeom = NULL;
204 0 : if (ParentOffset(i) == (unsigned int)iShape)
205 : {
206 0 : if ( ShapeType(i) == ST_LINESTRING )
207 0 : poGeom = ReadLineString(i);
208 : }
209 0 : if ( poGeom )
210 0 : poMultiLineString->addGeometryDirectly( poGeom );
211 : }
212 :
213 0 : return poMultiLineString;
214 : }
215 :
216 : /************************************************************************/
217 : /* ReadPolygon() */
218 : /************************************************************************/
219 :
220 0 : OGRPolygon* OGRMSSQLGeometryParser::ReadPolygon(int iShape)
221 : {
222 : int iFigure, iPoint, iNextPoint, i;
223 0 : int iNextFigure = NextFigureOffset(iShape);
224 :
225 0 : OGRPolygon* poPoly = new OGRPolygon();
226 0 : for (iFigure = FigureOffset(iShape); iFigure < iNextFigure; iFigure++)
227 : {
228 0 : OGRLinearRing* poRing = new OGRLinearRing();
229 0 : iPoint = PointOffset(iFigure);
230 0 : iNextPoint = NextPointOffset(iFigure);
231 0 : poRing->setNumPoints(iNextPoint - iPoint);
232 0 : i = 0;
233 0 : while (iPoint < iNextPoint)
234 : {
235 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
236 : {
237 0 : if ( chProps & SP_HASZVALUES )
238 0 : poRing->setPoint(i, ReadY(iPoint), ReadX(iPoint), ReadZ(iPoint) );
239 : else
240 0 : poRing->setPoint(i, ReadY(iPoint), ReadX(iPoint) );
241 : }
242 : else
243 : {
244 0 : if ( chProps & SP_HASZVALUES )
245 0 : poRing->setPoint(i, ReadX(iPoint), ReadY(iPoint), ReadZ(iPoint) );
246 : else
247 0 : poRing->setPoint(i, ReadX(iPoint), ReadY(iPoint) );
248 : }
249 :
250 0 : ++iPoint;
251 0 : ++i;
252 : }
253 0 : poPoly->addRingDirectly( poRing );
254 : }
255 0 : return poPoly;
256 : }
257 :
258 : /************************************************************************/
259 : /* ReadMultiPolygon() */
260 : /************************************************************************/
261 :
262 0 : OGRMultiPolygon* OGRMSSQLGeometryParser::ReadMultiPolygon(int iShape)
263 : {
264 : int i;
265 0 : OGRMultiPolygon* poMultiPolygon = new OGRMultiPolygon();
266 : OGRGeometry* poGeom;
267 :
268 0 : for (i = iShape + 1; i < nNumShapes; i++)
269 : {
270 0 : poGeom = NULL;
271 0 : if (ParentOffset(i) == (unsigned int)iShape)
272 : {
273 0 : if ( ShapeType(i) == ST_POLYGON )
274 0 : poGeom = ReadPolygon(i);
275 : }
276 0 : if ( poGeom )
277 0 : poMultiPolygon->addGeometryDirectly( poGeom );
278 : }
279 :
280 0 : return poMultiPolygon;
281 : }
282 :
283 : /************************************************************************/
284 : /* ReadGeometryCollection() */
285 : /************************************************************************/
286 :
287 0 : OGRGeometryCollection* OGRMSSQLGeometryParser::ReadGeometryCollection(int iShape)
288 : {
289 : int i;
290 0 : OGRGeometryCollection* poGeomColl = new OGRGeometryCollection();
291 : OGRGeometry* poGeom;
292 :
293 0 : for (i = iShape + 1; i < nNumShapes; i++)
294 : {
295 0 : poGeom = NULL;
296 0 : if (ParentOffset(i) == (unsigned int)iShape)
297 : {
298 0 : switch (ShapeType(i))
299 : {
300 : case ST_POINT:
301 0 : poGeom = ReadPoint(i);
302 0 : break;
303 : case ST_LINESTRING:
304 0 : poGeom = ReadLineString(i);
305 0 : break;
306 : case ST_POLYGON:
307 0 : poGeom = ReadPolygon(i);
308 0 : break;
309 : case ST_MULTIPOINT:
310 0 : poGeom = ReadMultiPoint(i);
311 0 : break;
312 : case ST_MULTILINESTRING:
313 0 : poGeom = ReadMultiLineString(i);
314 0 : break;
315 : case ST_MULTIPOLYGON:
316 0 : poGeom = ReadMultiPolygon(i);
317 0 : break;
318 : case ST_GEOMETRYCOLLECTION:
319 0 : poGeom = ReadGeometryCollection(i);
320 : break;
321 : }
322 : }
323 0 : if ( poGeom )
324 0 : poGeomColl->addGeometryDirectly( poGeom );
325 : }
326 :
327 0 : return poGeomColl;
328 : }
329 :
330 : /************************************************************************/
331 : /* ParseSqlGeometry() */
332 : /************************************************************************/
333 :
334 :
335 0 : OGRErr OGRMSSQLGeometryParser::ParseSqlGeometry(unsigned char* pszInput,
336 : int nLen, OGRGeometry **poGeom)
337 : {
338 0 : if (nLen < 10)
339 0 : return OGRERR_NOT_ENOUGH_DATA;
340 :
341 0 : pszData = pszInput;
342 :
343 : /* store the SRS id for further use */
344 0 : nSRSId = ReadInt32(0);
345 :
346 0 : if ( ReadByte(4) != 1 )
347 : {
348 0 : return OGRERR_CORRUPT_DATA;
349 : }
350 :
351 0 : chProps = ReadByte(5);
352 :
353 0 : if ( chProps & SP_HASMVALUES )
354 0 : nPointSize = 32;
355 0 : else if ( chProps & SP_HASZVALUES )
356 0 : nPointSize = 24;
357 : else
358 0 : nPointSize = 16;
359 :
360 0 : if ( chProps & SP_ISSINGLEPOINT )
361 : {
362 : // single point geometry
363 0 : nPointPos = 6;
364 :
365 0 : if (nLen < 6 + nPointSize)
366 : {
367 0 : return OGRERR_NOT_ENOUGH_DATA;
368 : }
369 :
370 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
371 : {
372 0 : if (chProps & SP_HASZVALUES)
373 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0), ReadZ(0));
374 : else
375 0 : *poGeom = new OGRPoint(ReadY(0), ReadX(0));
376 : }
377 : else
378 : {
379 0 : if (chProps & SP_HASZVALUES)
380 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0), ReadZ(0));
381 : else
382 0 : *poGeom = new OGRPoint(ReadX(0), ReadY(0));
383 : }
384 : }
385 0 : else if ( chProps & SP_ISSINGLELINESEGMENT )
386 : {
387 : // single line segment with 2 points
388 0 : nPointPos = 6;
389 :
390 0 : if (nLen < 6 + 2 * nPointSize)
391 : {
392 0 : return OGRERR_NOT_ENOUGH_DATA;
393 : }
394 :
395 0 : OGRLineString* line = new OGRLineString();
396 0 : line->setNumPoints(2);
397 :
398 0 : if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
399 : {
400 0 : if ( chProps & SP_HASZVALUES )
401 : {
402 0 : line->setPoint(0, ReadY(0), ReadX(0), ReadZ(0));
403 0 : line->setPoint(1, ReadY(1), ReadX(1), ReadZ(1));
404 : }
405 : else
406 : {
407 0 : line->setPoint(0, ReadY(0), ReadX(0));
408 0 : line->setPoint(1, ReadY(1), ReadX(1));
409 : }
410 : }
411 : else
412 : {
413 0 : if ( chProps & SP_HASZVALUES )
414 : {
415 0 : line->setPoint(0, ReadX(0), ReadY(0), ReadZ(0));
416 0 : line->setPoint(1, ReadX(1), ReadY(1), ReadZ(1));
417 : }
418 : else
419 : {
420 0 : line->setPoint(0, ReadX(0), ReadY(0));
421 0 : line->setPoint(1, ReadX(1), ReadY(1));
422 : }
423 : }
424 :
425 0 : *poGeom = line;
426 : }
427 : else
428 : {
429 : // complex geometries
430 0 : nNumPoints = ReadInt32(6);
431 :
432 0 : if ( nNumPoints <= 0 )
433 : {
434 0 : return OGRERR_NONE;
435 : }
436 :
437 : // position of the point array
438 0 : nPointPos = 10;
439 :
440 : // position of the figures
441 0 : nFigurePos = nPointPos + nPointSize * nNumPoints + 4;
442 :
443 0 : if (nLen < nFigurePos)
444 : {
445 0 : return OGRERR_NOT_ENOUGH_DATA;
446 : }
447 :
448 0 : nNumFigures = ReadInt32(nFigurePos - 4);
449 :
450 0 : if ( nNumFigures <= 0 )
451 : {
452 0 : return OGRERR_NONE;
453 : }
454 :
455 : // position of the shapes
456 0 : nShapePos = nFigurePos + 5 * nNumFigures + 4;
457 :
458 0 : if (nLen < nShapePos)
459 : {
460 0 : return OGRERR_NOT_ENOUGH_DATA;
461 : }
462 :
463 0 : nNumShapes = ReadInt32(nShapePos - 4);
464 :
465 0 : if (nLen < nShapePos + 9 * nNumShapes)
466 : {
467 0 : return OGRERR_NOT_ENOUGH_DATA;
468 : }
469 :
470 0 : if ( nNumShapes <= 0 )
471 : {
472 0 : return OGRERR_NONE;
473 : }
474 :
475 : // pick up the root shape
476 0 : if ( ParentOffset(0) != 0xFFFFFFFF)
477 : {
478 0 : return OGRERR_CORRUPT_DATA;
479 : }
480 :
481 : // determine the shape type
482 0 : switch (ShapeType(0))
483 : {
484 : case ST_POINT:
485 0 : *poGeom = ReadPoint(0);
486 0 : break;
487 : case ST_LINESTRING:
488 0 : *poGeom = ReadLineString(0);
489 0 : break;
490 : case ST_POLYGON:
491 0 : *poGeom = ReadPolygon(0);
492 0 : break;
493 : case ST_MULTIPOINT:
494 0 : *poGeom = ReadMultiPoint(0);
495 0 : break;
496 : case ST_MULTILINESTRING:
497 0 : *poGeom = ReadMultiLineString(0);
498 0 : break;
499 : case ST_MULTIPOLYGON:
500 0 : *poGeom = ReadMultiPolygon(0);
501 0 : break;
502 : case ST_GEOMETRYCOLLECTION:
503 0 : *poGeom = ReadGeometryCollection(0);
504 0 : break;
505 : default:
506 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
507 : }
508 : }
509 :
510 0 : return OGRERR_NONE;
511 : }
512 :
|