1 : /******************************************************************************
2 : * $Id: gml2ogrgeometry.cpp 18085 2009-11-23 19:02:18Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Code to translate between GML and OGR geometry forms.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
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 OR
22 : * 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 : * Independent Security Audit 2003/04/17 Andrey Kiselev:
31 : * Completed audit of this module. All functions may be used without buffer
32 : * overflows and stack corruptions with any kind of input data.
33 : *
34 : * Security Audit 2003/03/28 warmerda:
35 : * Completed security audit. I believe that this module may be safely used
36 : * to parse, arbitrary GML potentially provided by a hostile source without
37 : * compromising the system.
38 : *
39 : */
40 :
41 : #include "cpl_minixml.h"
42 : #include "ogr_geometry.h"
43 : #include "ogr_api.h"
44 : #include "cpl_error.h"
45 : #include "cpl_string.h"
46 : #include <ctype.h>
47 : #include "ogr_p.h"
48 :
49 : /************************************************************************/
50 : /* BareGMLElement() */
51 : /* */
52 : /* Returns the passed string with any namespace prefix */
53 : /* stripped off. */
54 : /************************************************************************/
55 :
56 349 : static const char *BareGMLElement( const char *pszInput )
57 :
58 : {
59 : const char *pszReturn;
60 :
61 349 : pszReturn = strchr( pszInput, ':' );
62 349 : if( pszReturn == NULL )
63 146 : pszReturn = pszInput;
64 : else
65 203 : pszReturn++;
66 :
67 349 : return pszReturn;
68 : }
69 :
70 : /************************************************************************/
71 : /* FindBareXMLChild() */
72 : /* */
73 : /* Find a child node with the indicated "bare" name, that is */
74 : /* after any namespace qualifiers have been stripped off. */
75 : /************************************************************************/
76 :
77 133 : static const CPLXMLNode *FindBareXMLChild( const CPLXMLNode *psParent,
78 : const char *pszBareName )
79 :
80 : {
81 133 : const CPLXMLNode *psCandidate = psParent->psChild;
82 :
83 307 : while( psCandidate != NULL )
84 : {
85 151 : if( psCandidate->eType == CXT_Element
86 : && EQUAL(BareGMLElement(psCandidate->pszValue), pszBareName) )
87 110 : return psCandidate;
88 :
89 41 : psCandidate = psCandidate->psNext;
90 : }
91 :
92 23 : return NULL;
93 : }
94 :
95 : /************************************************************************/
96 : /* GetElementText() */
97 : /************************************************************************/
98 :
99 112 : static const char *GetElementText( const CPLXMLNode *psElement )
100 :
101 : {
102 112 : if( psElement == NULL )
103 0 : return NULL;
104 :
105 112 : const CPLXMLNode *psChild = psElement->psChild;
106 :
107 231 : while( psChild != NULL )
108 : {
109 119 : if( psChild->eType == CXT_Text )
110 112 : return psChild->pszValue;
111 :
112 7 : psChild = psChild->psNext;
113 : }
114 :
115 0 : return NULL;
116 : }
117 :
118 : /************************************************************************/
119 : /* AddPoint() */
120 : /* */
121 : /* Add a point to the passed geometry. */
122 : /************************************************************************/
123 :
124 358 : static int AddPoint( OGRGeometry *poGeometry,
125 : double dfX, double dfY, double dfZ, int nDimension )
126 :
127 : {
128 650 : if( poGeometry->getGeometryType() == wkbPoint
129 292 : || poGeometry->getGeometryType() == wkbPoint25D )
130 : {
131 66 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
132 :
133 66 : if( poPoint->getX() != 0.0 || poPoint->getY() != 0.0 )
134 : {
135 : CPLError( CE_Failure, CPLE_AppDefined,
136 0 : "More than one coordinate for <Point> element.");
137 0 : return FALSE;
138 : }
139 :
140 66 : poPoint->setX( dfX );
141 66 : poPoint->setY( dfY );
142 66 : if( nDimension == 3 )
143 4 : poPoint->setZ( dfZ );
144 :
145 66 : return TRUE;
146 : }
147 :
148 310 : else if( poGeometry->getGeometryType() == wkbLineString
149 18 : || poGeometry->getGeometryType() == wkbLineString25D )
150 : {
151 292 : if( nDimension == 3 )
152 24 : ((OGRLineString *) poGeometry)->addPoint( dfX, dfY, dfZ );
153 : else
154 268 : ((OGRLineString *) poGeometry)->addPoint( dfX, dfY );
155 :
156 292 : return TRUE;
157 : }
158 :
159 : else
160 : {
161 : CPLAssert( FALSE );
162 0 : return FALSE;
163 : }
164 : }
165 :
166 : /************************************************************************/
167 : /* ParseGMLCoordinates() */
168 : /************************************************************************/
169 :
170 103 : static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeometry )
171 :
172 : {
173 103 : const CPLXMLNode *psCoordinates = FindBareXMLChild( psGeomNode, "coordinates" );
174 103 : int iCoord = 0;
175 :
176 : /* -------------------------------------------------------------------- */
177 : /* Handle <coordinates> case. */
178 : /* -------------------------------------------------------------------- */
179 103 : if( psCoordinates != NULL )
180 : {
181 85 : const char *pszCoordString = GetElementText( psCoordinates );
182 :
183 85 : if( pszCoordString == NULL )
184 : {
185 : CPLError( CE_Failure, CPLE_AppDefined,
186 0 : "<coordinates> element missing value." );
187 0 : return FALSE;
188 : }
189 :
190 475 : while( *pszCoordString != '\0' )
191 : {
192 305 : double dfX, dfY, dfZ = 0.0;
193 305 : int nDimension = 2;
194 :
195 : // parse out 2 or 3 tuple.
196 305 : dfX = OGRFastAtof( pszCoordString );
197 3461 : while( *pszCoordString != '\0'
198 : && *pszCoordString != ','
199 : && !isspace((unsigned char)*pszCoordString) )
200 2851 : pszCoordString++;
201 :
202 305 : if( *pszCoordString == '\0' || isspace((unsigned char)*pszCoordString) )
203 : {
204 : CPLError( CE_Failure, CPLE_AppDefined,
205 0 : "Corrupt <coordinates> value." );
206 0 : return FALSE;
207 : }
208 :
209 305 : pszCoordString++;
210 305 : dfY = OGRFastAtof( pszCoordString );
211 3532 : while( *pszCoordString != '\0'
212 : && *pszCoordString != ','
213 : && !isspace((unsigned char)*pszCoordString) )
214 2922 : pszCoordString++;
215 :
216 305 : if( *pszCoordString == ',' )
217 : {
218 24 : pszCoordString++;
219 24 : dfZ = OGRFastAtof( pszCoordString );
220 24 : nDimension = 3;
221 72 : while( *pszCoordString != '\0'
222 : && *pszCoordString != ','
223 : && !isspace((unsigned char)*pszCoordString) )
224 24 : pszCoordString++;
225 : }
226 :
227 833 : while( isspace((unsigned char)*pszCoordString) )
228 223 : pszCoordString++;
229 :
230 305 : if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
231 0 : return FALSE;
232 :
233 305 : iCoord++;
234 : }
235 :
236 85 : return iCoord > 0;
237 : }
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Is this a "pos"? GML 3 construct. */
241 : /* Parse if it exist a series of pos elements (this would allow */
242 : /* the correct parsing of gml3.1.1 geomtries such as linestring */
243 : /* defined with pos elements. */
244 : /* -------------------------------------------------------------------- */
245 : const CPLXMLNode *psPos;
246 :
247 18 : int bHasFoundPosElement = FALSE;
248 44 : for( psPos = psGeomNode->psChild;
249 : psPos != NULL;
250 : psPos = psPos->psNext )
251 : {
252 26 : if( psPos->eType != CXT_Element
253 : || !EQUAL(BareGMLElement(psPos->pszValue),"pos") )
254 10 : continue;
255 :
256 : char **papszTokens = CSLTokenizeStringComplex(
257 16 : GetElementText( psPos ), " ,", FALSE, FALSE );
258 16 : int bSuccess = FALSE;
259 :
260 16 : if( CSLCount( papszTokens ) > 2 )
261 : {
262 : bSuccess = AddPoint( poGeometry,
263 1 : OGRFastAtof(papszTokens[0]),
264 1 : OGRFastAtof(papszTokens[1]),
265 3 : OGRFastAtof(papszTokens[2]), 3 );
266 : }
267 15 : else if( CSLCount( papszTokens ) > 1 )
268 : {
269 : bSuccess = AddPoint( poGeometry,
270 15 : OGRFastAtof(papszTokens[0]),
271 15 : OGRFastAtof(papszTokens[1]),
272 45 : 0.0, 2 );
273 : }
274 : else
275 : {
276 : CPLError( CE_Failure, CPLE_AppDefined,
277 : "Did not get 2+ values in <gml:pos>%s</gml:pos> tuple.",
278 0 : GetElementText( psPos ) );
279 : }
280 :
281 16 : CSLDestroy( papszTokens );
282 :
283 16 : if (bSuccess)
284 16 : bHasFoundPosElement = TRUE;
285 : else
286 0 : return FALSE;
287 : }
288 :
289 18 : if (bHasFoundPosElement)
290 8 : return TRUE;
291 :
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Is this a "posList"? GML 3 construct (SF profile). */
295 : /* -------------------------------------------------------------------- */
296 10 : const CPLXMLNode *psPosList = FindBareXMLChild( psGeomNode, "posList" );
297 :
298 10 : if( psPosList != NULL )
299 : {
300 : char **papszTokens;
301 10 : int bSuccess = FALSE;
302 10 : int i=0, nCount=0;
303 : const CPLXMLNode* psChild;
304 10 : int nDimension = 2;
305 :
306 : /* Try to detect the presence of an srsDimension attribute */
307 : /* This attribute is only availabe for gml3.1.1 but not */
308 : /* available for gml3.1 SF*/
309 10 : psChild = psPosList->psChild;
310 20 : while (psChild != NULL)
311 : {
312 10 : if (psChild->eType == CXT_Attribute &&
313 : EQUAL(psChild->pszValue, "srsDimension"))
314 : {
315 1 : nDimension = atoi(psChild->psChild->pszValue);
316 1 : break;
317 : }
318 9 : else if (psChild->eType != CXT_Attribute)
319 : {
320 9 : break;
321 : }
322 0 : psChild = psChild->psNext;
323 : }
324 :
325 10 : if (nDimension != 2 && nDimension != 3)
326 : {
327 : CPLError( CE_Failure, CPLE_AppDefined,
328 0 : "srsDimension = %d not supported", nDimension);
329 0 : return FALSE;
330 : }
331 :
332 : papszTokens = CSLTokenizeStringComplex(
333 10 : GetElementText( psPosList ), " ,", FALSE, FALSE );
334 :
335 10 : nCount = CSLCount( papszTokens );
336 :
337 11 : if (nCount < nDimension || (nCount % nDimension) != 0)
338 : {
339 : CPLError( CE_Failure, CPLE_AppDefined,
340 : "Did not get at least %d values or invalid number of \n"
341 : "set of coordinates <gml:posList>%s</gml:posList>",
342 1 : nDimension, GetElementText( psPosList ) );
343 : }
344 : else
345 : {
346 9 : i=0;
347 55 : while (i<nCount)
348 : {
349 : bSuccess = AddPoint( poGeometry,
350 37 : OGRFastAtof(papszTokens[i]),
351 37 : OGRFastAtof(papszTokens[i+1]),
352 111 : (nDimension == 3) ? OGRFastAtof(papszTokens[i+2]) : 0.0, nDimension );
353 37 : i+=nDimension;
354 : }
355 : }
356 10 : CSLDestroy( papszTokens );
357 :
358 10 : return bSuccess;
359 : }
360 :
361 :
362 : /* -------------------------------------------------------------------- */
363 : /* Handle form with a list of <coord> items each with an <X>, */
364 : /* and <Y> element. */
365 : /* -------------------------------------------------------------------- */
366 : const CPLXMLNode *psCoordNode;
367 :
368 0 : for( psCoordNode = psGeomNode->psChild;
369 : psCoordNode != NULL;
370 : psCoordNode = psCoordNode->psNext )
371 : {
372 0 : if( psCoordNode->eType != CXT_Element
373 : || !EQUAL(BareGMLElement(psCoordNode->pszValue),"coord") )
374 0 : continue;
375 :
376 : const CPLXMLNode *psXNode, *psYNode, *psZNode;
377 0 : double dfX, dfY, dfZ = 0.0;
378 0 : int nDimension = 2;
379 :
380 0 : psXNode = FindBareXMLChild( psCoordNode, "X" );
381 0 : psYNode = FindBareXMLChild( psCoordNode, "Y" );
382 0 : psZNode = FindBareXMLChild( psCoordNode, "Z" );
383 :
384 0 : if( psXNode == NULL || psYNode == NULL
385 : || GetElementText(psXNode) == NULL
386 : || GetElementText(psYNode) == NULL
387 : || (psZNode != NULL && GetElementText(psZNode) == NULL) )
388 : {
389 : CPLError( CE_Failure, CPLE_AppDefined,
390 0 : "Corrupt <coord> element, missing <X> or <Y> element?" );
391 0 : return FALSE;
392 : }
393 :
394 0 : dfX = OGRFastAtof( GetElementText(psXNode) );
395 0 : dfY = OGRFastAtof( GetElementText(psYNode) );
396 :
397 0 : if( psZNode != NULL && GetElementText(psZNode) != NULL )
398 : {
399 0 : dfZ = OGRFastAtof( GetElementText(psZNode) );
400 0 : nDimension = 3;
401 : }
402 :
403 0 : if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
404 0 : return FALSE;
405 :
406 0 : iCoord++;
407 : }
408 :
409 0 : return iCoord > 0.0;
410 : }
411 :
412 : /************************************************************************/
413 : /* GML2OGRGeometry_XMLNode() */
414 : /* */
415 : /* Translates the passed XMLnode and it's children into an */
416 : /* OGRGeometry. This is used recursively for geometry */
417 : /* collections. */
418 : /************************************************************************/
419 :
420 124 : static OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode )
421 :
422 : {
423 124 : const char *pszBaseGeometry = BareGMLElement( psNode->pszValue );
424 :
425 : /* -------------------------------------------------------------------- */
426 : /* Polygon */
427 : /* -------------------------------------------------------------------- */
428 124 : if( EQUAL(pszBaseGeometry,"Polygon") )
429 : {
430 : const CPLXMLNode *psChild;
431 15 : OGRPolygon *poPolygon = new OGRPolygon();
432 : OGRLinearRing *poRing;
433 :
434 : // Find outer ring.
435 15 : psChild = FindBareXMLChild( psNode, "outerBoundaryIs" );
436 15 : if (psChild == NULL)
437 5 : psChild = FindBareXMLChild( psNode, "exterior");
438 :
439 15 : if( psChild == NULL || psChild->psChild == NULL )
440 : {
441 : CPLError( CE_Failure, CPLE_AppDefined,
442 0 : "Missing outerBoundaryIs property on Polygon." );
443 0 : delete poPolygon;
444 0 : return NULL;
445 : }
446 :
447 : // Translate outer ring and add to polygon.
448 : poRing = (OGRLinearRing *)
449 15 : GML2OGRGeometry_XMLNode( psChild->psChild );
450 15 : if( poRing == NULL )
451 : {
452 0 : delete poPolygon;
453 0 : return NULL;
454 : }
455 :
456 15 : if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
457 : {
458 : CPLError( CE_Failure, CPLE_AppDefined,
459 : "Got %.500s geometry as outerBoundaryIs instead of LINEARRING.",
460 0 : poRing->getGeometryName() );
461 0 : delete poPolygon;
462 0 : delete poRing;
463 0 : return NULL;
464 : }
465 :
466 15 : poPolygon->addRingDirectly( poRing );
467 :
468 : // Find all inner rings
469 37 : for( psChild = psNode->psChild;
470 : psChild != NULL;
471 : psChild = psChild->psNext )
472 : {
473 22 : if( psChild->eType == CXT_Element
474 : && (EQUAL(BareGMLElement(psChild->pszValue),"innerBoundaryIs") ||
475 : EQUAL(BareGMLElement(psChild->pszValue),"interior")))
476 : {
477 : poRing = (OGRLinearRing *)
478 4 : GML2OGRGeometry_XMLNode( psChild->psChild );
479 4 : if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
480 : {
481 : CPLError( CE_Failure, CPLE_AppDefined,
482 : "Got %.500s geometry as innerBoundaryIs instead of LINEARRING.",
483 0 : poRing->getGeometryName() );
484 0 : delete poPolygon;
485 0 : delete poRing;
486 0 : return NULL;
487 : }
488 :
489 4 : poPolygon->addRingDirectly( poRing );
490 : }
491 : }
492 :
493 15 : return poPolygon;
494 : }
495 :
496 : /* -------------------------------------------------------------------- */
497 : /* LinearRing */
498 : /* -------------------------------------------------------------------- */
499 109 : if( EQUAL(pszBaseGeometry,"LinearRing") )
500 : {
501 19 : OGRLinearRing *poLinearRing = new OGRLinearRing();
502 :
503 19 : if( !ParseGMLCoordinates( psNode, poLinearRing ) )
504 : {
505 0 : delete poLinearRing;
506 0 : return NULL;
507 : }
508 :
509 19 : return poLinearRing;
510 : }
511 :
512 : /* -------------------------------------------------------------------- */
513 : /* LineString */
514 : /* -------------------------------------------------------------------- */
515 90 : if( EQUAL(pszBaseGeometry,"LineString") )
516 : {
517 18 : OGRLineString *poLine = new OGRLineString();
518 :
519 18 : if( !ParseGMLCoordinates( psNode, poLine ) )
520 : {
521 1 : delete poLine;
522 1 : return NULL;
523 : }
524 :
525 17 : return poLine;
526 : }
527 :
528 : /* -------------------------------------------------------------------- */
529 : /* PointType */
530 : /* -------------------------------------------------------------------- */
531 72 : if( EQUAL(pszBaseGeometry,"PointType")
532 : || EQUAL(pszBaseGeometry,"Point") )
533 : {
534 66 : OGRPoint *poPoint = new OGRPoint();
535 :
536 66 : if( !ParseGMLCoordinates( psNode, poPoint ) )
537 : {
538 0 : delete poPoint;
539 0 : return NULL;
540 : }
541 :
542 66 : return poPoint;
543 : }
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Box */
547 : /* -------------------------------------------------------------------- */
548 6 : if( EQUAL(pszBaseGeometry,"BoxType") || EQUAL(pszBaseGeometry,"Box") )
549 : {
550 0 : OGRLineString oPoints;
551 :
552 0 : if( !ParseGMLCoordinates( psNode, &oPoints ) )
553 0 : return NULL;
554 :
555 0 : if( oPoints.getNumPoints() < 2 )
556 0 : return NULL;
557 :
558 0 : OGRLinearRing *poBoxRing = new OGRLinearRing();
559 0 : OGRPolygon *poBoxPoly = new OGRPolygon();
560 :
561 0 : poBoxRing->setNumPoints( 5 );
562 : poBoxRing->setPoint(
563 0 : 0, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) );
564 : poBoxRing->setPoint(
565 0 : 1, oPoints.getX(1), oPoints.getY(0), oPoints.getZ(0) );
566 : poBoxRing->setPoint(
567 0 : 2, oPoints.getX(1), oPoints.getY(1), oPoints.getZ(1) );
568 : poBoxRing->setPoint(
569 0 : 3, oPoints.getX(0), oPoints.getY(1), oPoints.getZ(0) );
570 : poBoxRing->setPoint(
571 0 : 4, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) );
572 :
573 0 : poBoxPoly->addRingDirectly( poBoxRing );
574 :
575 0 : return poBoxPoly;
576 : }
577 :
578 : /* -------------------------------------------------------------------- */
579 : /* MultiPolygon */
580 : /* -------------------------------------------------------------------- */
581 6 : if( EQUAL(pszBaseGeometry,"MultiPolygon") ||
582 : EQUAL(pszBaseGeometry,"MultiSurface") )
583 : {
584 : const CPLXMLNode *psChild;
585 1 : OGRMultiPolygon *poMPoly = new OGRMultiPolygon();
586 :
587 : // Find all inner rings
588 3 : for( psChild = psNode->psChild;
589 : psChild != NULL;
590 : psChild = psChild->psNext )
591 : {
592 2 : if( psChild->eType == CXT_Element
593 : && (EQUAL(BareGMLElement(psChild->pszValue),"polygonMember") ||
594 : EQUAL(BareGMLElement(psChild->pszValue),"surfaceMember")) )
595 : {
596 : OGRPolygon *poPolygon;
597 :
598 : poPolygon = (OGRPolygon *)
599 2 : GML2OGRGeometry_XMLNode( psChild->psChild );
600 :
601 2 : if( poPolygon == NULL )
602 : {
603 0 : delete poMPoly;
604 0 : return NULL;
605 : }
606 :
607 2 : if( !EQUAL(poPolygon->getGeometryName(),"POLYGON") )
608 : {
609 : CPLError( CE_Failure, CPLE_AppDefined,
610 : "Got %.500s geometry as polygonMember instead of MULTIPOLYGON.",
611 0 : poPolygon->getGeometryName() );
612 0 : delete poPolygon;
613 0 : delete poMPoly;
614 0 : return NULL;
615 : }
616 :
617 2 : poMPoly->addGeometryDirectly( poPolygon );
618 : }
619 : }
620 :
621 1 : return poMPoly;
622 : }
623 :
624 : /* -------------------------------------------------------------------- */
625 : /* MultiPoint */
626 : /* -------------------------------------------------------------------- */
627 5 : if( EQUAL(pszBaseGeometry,"MultiPoint") )
628 : {
629 : const CPLXMLNode *psChild;
630 2 : OGRMultiPoint *poMP = new OGRMultiPoint();
631 :
632 : // collect points.
633 8 : for( psChild = psNode->psChild;
634 : psChild != NULL;
635 : psChild = psChild->psNext )
636 : {
637 6 : if( psChild->eType == CXT_Element
638 : && EQUAL(BareGMLElement(psChild->pszValue),"pointMember") )
639 : {
640 : OGRPoint *poPoint;
641 :
642 : poPoint = (OGRPoint *)
643 6 : GML2OGRGeometry_XMLNode( psChild->psChild );
644 12 : if( poPoint == NULL
645 6 : || wkbFlatten(poPoint->getGeometryType()) != wkbPoint )
646 : {
647 : CPLError( CE_Failure, CPLE_AppDefined,
648 : "Got %.500s geometry as pointMember instead of MULTIPOINT",
649 0 : poPoint ? poPoint->getGeometryName() : "NULL" );
650 0 : delete poPoint;
651 0 : delete poMP;
652 0 : return NULL;
653 : }
654 :
655 6 : poMP->addGeometryDirectly( poPoint );
656 : }
657 : }
658 :
659 2 : return poMP;
660 : }
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* MultiLineString */
664 : /* -------------------------------------------------------------------- */
665 3 : if( EQUAL(pszBaseGeometry,"MultiLineString") )
666 : {
667 : const CPLXMLNode *psChild;
668 1 : OGRMultiLineString *poMP = new OGRMultiLineString();
669 :
670 : // collect lines
671 5 : for( psChild = psNode->psChild;
672 : psChild != NULL;
673 : psChild = psChild->psNext )
674 : {
675 4 : if( psChild->eType == CXT_Element
676 : && EQUAL(BareGMLElement(psChild->pszValue),"lineStringMember") )
677 : {
678 : OGRGeometry *poGeom;
679 :
680 4 : poGeom = GML2OGRGeometry_XMLNode( psChild->psChild );
681 8 : if( poGeom == NULL
682 4 : || wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
683 : {
684 : CPLError( CE_Failure, CPLE_AppDefined,
685 : "Got %.500s geometry as Member instead of LINESTRING.",
686 0 : poGeom ? poGeom->getGeometryName() : "NULL" );
687 0 : delete poGeom;
688 0 : delete poMP;
689 0 : return NULL;
690 : }
691 :
692 4 : poMP->addGeometryDirectly( poGeom );
693 : }
694 : }
695 :
696 1 : return poMP;
697 : }
698 :
699 : /* -------------------------------------------------------------------- */
700 : /* GeometryCollection */
701 : /* -------------------------------------------------------------------- */
702 2 : if( EQUAL(pszBaseGeometry,"GeometryCollection") )
703 : {
704 : const CPLXMLNode *psChild;
705 2 : OGRGeometryCollection *poGC = new OGRGeometryCollection();
706 :
707 : // collect geoms
708 10 : for( psChild = psNode->psChild;
709 : psChild != NULL;
710 : psChild = psChild->psNext )
711 : {
712 8 : if( psChild->eType == CXT_Element
713 : && EQUAL(BareGMLElement(psChild->pszValue),"geometryMember") )
714 : {
715 : OGRGeometry *poGeom;
716 :
717 8 : poGeom = GML2OGRGeometry_XMLNode( psChild->psChild );
718 8 : if( poGeom == NULL )
719 : {
720 : CPLError( CE_Failure, CPLE_AppDefined,
721 0 : "Failed to get geometry in geometryMember" );
722 0 : delete poGeom;
723 0 : delete poGC;
724 0 : return NULL;
725 : }
726 :
727 8 : poGC->addGeometryDirectly( poGeom );
728 : }
729 : }
730 :
731 2 : return poGC;
732 : }
733 :
734 : CPLError( CE_Failure, CPLE_AppDefined,
735 : "Unrecognised geometry type <%.500s>.",
736 0 : pszBaseGeometry );
737 :
738 0 : return NULL;
739 : }
740 :
741 : /************************************************************************/
742 : /* OGR_G_CreateFromGMLTree() */
743 : /************************************************************************/
744 :
745 2 : OGRGeometryH OGR_G_CreateFromGMLTree( const CPLXMLNode *psTree )
746 :
747 : {
748 2 : return (OGRGeometryH) GML2OGRGeometry_XMLNode( psTree );
749 : }
750 :
751 : /************************************************************************/
752 : /* OGR_G_CreateFromGML() */
753 : /************************************************************************/
754 :
755 83 : OGRGeometryH OGR_G_CreateFromGML( const char *pszGML )
756 :
757 : {
758 83 : if( pszGML == NULL || strlen(pszGML) == 0 )
759 : {
760 : CPLError( CE_Failure, CPLE_AppDefined,
761 0 : "GML Geometry is empty in GML2OGRGeometry()." );
762 0 : return NULL;
763 : }
764 :
765 : /* ------------------------------------------------------------ -------- */
766 : /* Try to parse the XML snippet using the MiniXML API. If this */
767 : /* fails, we assume the minixml api has already posted a CPL */
768 : /* error, and just return NULL. */
769 : /* -------------------------------------------------------------------- */
770 83 : CPLXMLNode *psGML = CPLParseXMLString( pszGML );
771 :
772 83 : if( psGML == NULL )
773 0 : return NULL;
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Convert geometry recursively. */
777 : /* -------------------------------------------------------------------- */
778 : OGRGeometry *poGeometry;
779 :
780 83 : poGeometry = GML2OGRGeometry_XMLNode( psGML );
781 :
782 83 : CPLDestroyXMLNode( psGML );
783 :
784 83 : return (OGRGeometryH) poGeometry;
785 : }
|