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