LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - gmlhandler.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 528 357 67.6 %
Date: 2011-12-18 Functions: 44 29 65.9 %

       1                 : /**********************************************************************
       2                 :  * $Id: gmlhandler.cpp 23566 2011-12-13 20:51:04Z rouault $
       3                 :  *
       4                 :  * Project:  GML Reader
       5                 :  * Purpose:  Implementation of GMLHandler class.
       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                 : #include <ctype.h>
      31                 : #include "gmlreaderp.h"
      32                 : #include "cpl_conv.h"
      33                 : #include "cpl_string.h"
      34                 : #include "cpl_hash_set.h"
      35                 : 
      36                 : #ifdef HAVE_XERCES
      37                 : 
      38                 : /* Must be a multiple of 4 */
      39                 : #define MAX_TOKEN_SIZE  1000
      40                 : 
      41                 : /************************************************************************/
      42                 : /*                        GMLXercesHandler()                            */
      43                 : /************************************************************************/
      44                 : 
      45               0 : GMLXercesHandler::GMLXercesHandler( GMLReader *poReader ) : GMLHandler(poReader)
      46                 : {
      47               0 :     m_nEntityCounter = 0;
      48               0 : }
      49                 : 
      50                 : /************************************************************************/
      51                 : /*                            startElement()                            */
      52                 : /************************************************************************/
      53                 : 
      54               0 : void GMLXercesHandler::startElement(const XMLCh* const    uri,
      55                 :                                     const XMLCh* const    localname,
      56                 :                                     const XMLCh* const    qname,
      57                 :                                     const Attributes& attrs )
      58                 : 
      59                 : {
      60                 :     char        szElementName[MAX_TOKEN_SIZE];
      61                 : 
      62               0 :     m_nEntityCounter = 0;
      63                 : 
      64                 :     /* A XMLCh character can expand to 4 bytes in UTF-8 */
      65               0 :     if (4 * tr_strlen( localname ) >= MAX_TOKEN_SIZE)
      66                 :     {
      67                 :         static int bWarnOnce = FALSE;
      68               0 :         XMLCh* tempBuffer = (XMLCh*) CPLMalloc(sizeof(XMLCh) * (MAX_TOKEN_SIZE / 4 + 1));
      69               0 :         memcpy(tempBuffer, localname, sizeof(XMLCh) * (MAX_TOKEN_SIZE / 4));
      70               0 :         tempBuffer[MAX_TOKEN_SIZE / 4] = 0;
      71               0 :         tr_strcpy( szElementName, tempBuffer );
      72               0 :         CPLFree(tempBuffer);
      73               0 :         if (!bWarnOnce)
      74                 :         {
      75               0 :             bWarnOnce = TRUE;
      76               0 :             CPLError(CE_Warning, CPLE_AppDefined, "A too big element name has been truncated");
      77                 :         }
      78                 :     }
      79                 :     else
      80               0 :         tr_strcpy( szElementName, localname );
      81                 : 
      82               0 :     if (GMLHandler::startElement(szElementName, strlen(szElementName), (void*) &attrs) == OGRERR_NOT_ENOUGH_MEMORY)
      83                 :     {
      84               0 :         throw SAXNotSupportedException("Out of memory");
      85                 :     }
      86               0 : }
      87                 : 
      88                 : /************************************************************************/
      89                 : /*                             endElement()                             */
      90                 : /************************************************************************/
      91               0 : void GMLXercesHandler::endElement(const   XMLCh* const    uri,
      92                 :                                   const   XMLCh* const    localname,
      93                 :                                   const   XMLCh* const    qname )
      94                 : 
      95                 : {
      96               0 :     m_nEntityCounter = 0;
      97                 : 
      98               0 :     if (GMLHandler::endElement() == OGRERR_NOT_ENOUGH_MEMORY)
      99                 :     {
     100               0 :         throw SAXNotSupportedException("Out of memory");
     101                 :     }
     102               0 : }
     103                 : 
     104                 : /************************************************************************/
     105                 : /*                             characters()                             */
     106                 : /************************************************************************/
     107                 : 
     108               0 : void GMLXercesHandler::characters(const XMLCh* const chars_in,
     109                 : #if XERCES_VERSION_MAJOR >= 3
     110                 :                                   const XMLSize_t length
     111                 : #else
     112                 :                                   const unsigned int length
     113                 : #endif
     114                 :                                   )
     115                 : 
     116                 : {
     117               0 :     char* utf8String = tr_strdup(chars_in);
     118               0 :     int nLen = strlen(utf8String);
     119               0 :     OGRErr eErr = GMLHandler::dataHandler(utf8String, nLen);
     120               0 :     CPLFree(utf8String);
     121               0 :     if (eErr == OGRERR_NOT_ENOUGH_MEMORY)
     122                 :     {
     123               0 :         throw SAXNotSupportedException("Out of memory");
     124                 :     }
     125               0 : }
     126                 : 
     127                 : /************************************************************************/
     128                 : /*                             fatalError()                             */
     129                 : /************************************************************************/
     130                 : 
     131               0 : void GMLXercesHandler::fatalError( const SAXParseException &exception)
     132                 : 
     133                 : {
     134                 :     char *pszErrorMessage;
     135                 : 
     136               0 :     pszErrorMessage = tr_strdup( exception.getMessage() );
     137                 :     CPLError( CE_Failure, CPLE_AppDefined, 
     138                 :               "XML Parsing Error: %s\n", 
     139               0 :               pszErrorMessage );
     140                 : 
     141               0 :     CPLFree( pszErrorMessage );
     142               0 : }
     143                 : 
     144                 : /************************************************************************/
     145                 : /*                             startEntity()                            */
     146                 : /************************************************************************/
     147                 : 
     148               0 : void GMLXercesHandler::startEntity (const XMLCh *const name)
     149                 : {
     150               0 :     m_nEntityCounter ++;
     151               0 :     if (m_nEntityCounter > 1000 && !m_poReader->HasStoppedParsing())
     152                 :     {
     153               0 :         throw SAXNotSupportedException("File probably corrupted (million laugh pattern)");
     154                 :     }
     155               0 : }
     156                 : 
     157                 : /************************************************************************/
     158                 : /*                               GetFID()                               */
     159                 : /************************************************************************/
     160                 : 
     161               0 : const char* GMLXercesHandler::GetFID(void* attr)
     162                 : {
     163               0 :     const Attributes* attrs = (const Attributes*) attr;
     164                 :     int nFIDIndex;
     165                 :     XMLCh   anFID[100];
     166                 : 
     167               0 :     tr_strcpy( anFID, "fid" );
     168               0 :     nFIDIndex = attrs->getIndex( anFID );
     169               0 :     if( nFIDIndex != -1 )
     170                 :     {
     171               0 :         char* pszValue = tr_strdup( attrs->getValue( nFIDIndex ) );
     172               0 :         osFID.assign(pszValue);
     173               0 :         CPLFree(pszValue);
     174               0 :         return osFID.c_str();
     175                 :     }
     176                 :     else
     177                 :     {
     178               0 :         tr_strcpy( anFID, "gml:id" );
     179               0 :         nFIDIndex = attrs->getIndex( anFID );
     180               0 :         if( nFIDIndex != -1 )
     181                 :         {
     182               0 :             char* pszValue = tr_strdup( attrs->getValue( nFIDIndex ) );
     183               0 :             osFID.assign(pszValue);
     184               0 :             CPLFree(pszValue);
     185               0 :             return osFID.c_str();
     186                 :         }
     187                 :     }
     188                 : 
     189               0 :     osFID.resize(0);
     190               0 :     return NULL;
     191                 : }
     192                 : 
     193                 : /************************************************************************/
     194                 : /*                        AddAttributes()                               */
     195                 : /************************************************************************/
     196                 : 
     197               0 : CPLXMLNode* GMLXercesHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
     198                 : {
     199               0 :     const Attributes* attrs = (const Attributes*) attr;
     200                 : 
     201               0 :     CPLXMLNode* psLastChild = NULL;
     202                 : 
     203               0 :     for(unsigned int i=0; i < attrs->getLength(); i++)
     204                 :     {
     205               0 :         char* pszName = tr_strdup(attrs->getQName(i));
     206               0 :         char* pszValue = tr_strdup(attrs->getValue(i));
     207                 : 
     208               0 :         CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, pszName);
     209               0 :         CPLCreateXMLNode(psChild, CXT_Text, pszValue);
     210                 : 
     211               0 :         CPLFree(pszName);
     212               0 :         CPLFree(pszValue);
     213                 : 
     214               0 :         if (psLastChild == NULL)
     215               0 :             psNode->psChild = psChild;
     216                 :         else
     217               0 :             psLastChild->psNext = psChild;
     218               0 :         psLastChild = psChild;
     219                 :     }
     220                 : 
     221               0 :     return psLastChild;
     222                 : }
     223                 : 
     224                 : /************************************************************************/
     225                 : /*                    GetAttributeValue()                               */
     226                 : /************************************************************************/
     227                 : 
     228               0 : char* GMLXercesHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
     229                 : {
     230               0 :     const Attributes* attrs = (const Attributes*) attr;
     231               0 :     for(unsigned int i=0; i < attrs->getLength(); i++)
     232                 :     {
     233               0 :         char* pszString = tr_strdup(attrs->getQName(i));
     234               0 :         if (strcmp(pszString, pszAttributeName) == 0)
     235                 :         {
     236               0 :             CPLFree(pszString);
     237               0 :             return tr_strdup(attrs->getValue(i));
     238                 :         }
     239               0 :         CPLFree(pszString);
     240                 :     }
     241               0 :     return NULL;
     242                 : }
     243                 : 
     244                 : #endif
     245                 : 
     246                 : #ifdef HAVE_EXPAT
     247                 : 
     248                 : /************************************************************************/
     249                 : /*                            GMLExpatHandler()                         */
     250                 : /************************************************************************/
     251                 : 
     252             111 : GMLExpatHandler::GMLExpatHandler( GMLReader *poReader, XML_Parser oParser ) : GMLHandler(poReader)
     253                 : 
     254                 : {
     255             111 :     m_oParser = oParser;
     256             111 :     m_bStopParsing = FALSE;
     257             111 :     m_nDataHandlerCounter = 0;
     258             111 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                           startElementCbk()                          */
     262                 : /************************************************************************/
     263                 : 
     264           14797 : void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszName,
     265                 :                                               const char **ppszAttr)
     266                 : 
     267                 : {
     268           14797 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     269           14797 :     if (pThis->m_bStopParsing)
     270               0 :         return;
     271                 : 
     272           14797 :     const char* pszIter = pszName;
     273                 :     char ch;
     274          201287 :     while((ch = *pszIter) != '\0')
     275                 :     {
     276          171693 :         if (ch == ':')
     277           10864 :             pszName = pszIter + 1;
     278          171693 :         pszIter ++;
     279                 :     }
     280                 : 
     281           14797 :     if (pThis->GMLHandler::startElement(pszName, (int)(pszIter - pszName), ppszAttr) == OGRERR_NOT_ENOUGH_MEMORY)
     282                 :     {
     283               0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     284               0 :         pThis->m_bStopParsing = TRUE;
     285               0 :         XML_StopParser(pThis->m_oParser, XML_FALSE);
     286                 :     }
     287                 : 
     288                 : }
     289                 : 
     290                 : /************************************************************************/
     291                 : /*                            endElementCbk()                           */
     292                 : /************************************************************************/
     293           14790 : void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, const char* pszName )
     294                 : 
     295                 : {
     296           14790 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     297           14790 :     if (pThis->m_bStopParsing)
     298               0 :         return;
     299                 : 
     300           14790 :     if (pThis->GMLHandler::endElement() == OGRERR_NOT_ENOUGH_MEMORY)
     301                 :     {
     302               0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     303               0 :         pThis->m_bStopParsing = TRUE;
     304               0 :         XML_StopParser(pThis->m_oParser, XML_FALSE);
     305                 :     }
     306                 : }
     307                 : 
     308                 : /************************************************************************/
     309                 : /*                            dataHandlerCbk()                          */
     310                 : /************************************************************************/
     311                 : 
     312           39489 : void XMLCALL GMLExpatHandler::dataHandlerCbk(void *pUserData, const char *data, int nLen)
     313                 : 
     314                 : {
     315           39489 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     316           39489 :     if (pThis->m_bStopParsing)
     317               0 :         return;
     318                 : 
     319           39489 :     pThis->m_nDataHandlerCounter ++;
     320                 :     /* The size of the buffer that is fetched and that Expat parses is */
     321                 :     /* PARSER_BUF_SIZE bytes. If the dataHandlerCbk() callback is called */
     322                 :     /* more than PARSER_BUF_SIZE times, this means that one byte in the */
     323                 :     /* file expands to more XML text fragments, which is the sign of a */
     324                 :     /* likely abuse of <!ENTITY> */
     325                 :     /* Note: the counter is zeroed by ResetDataHandlerCounter() before each */
     326                 :     /* new XML parsing. */
     327           39489 :     if (pThis->m_nDataHandlerCounter >= PARSER_BUF_SIZE)
     328                 :     {
     329               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
     330               0 :         pThis->m_bStopParsing = TRUE;
     331               0 :         XML_StopParser(pThis->m_oParser, XML_FALSE);
     332               0 :         return;
     333                 :     }
     334                 : 
     335           39489 :     if (pThis->GMLHandler::dataHandler(data, nLen) == OGRERR_NOT_ENOUGH_MEMORY)
     336                 :     {
     337               0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     338               0 :         pThis->m_bStopParsing = TRUE;
     339               0 :         XML_StopParser(pThis->m_oParser, XML_FALSE);
     340               0 :         return;
     341                 :     }
     342                 : }
     343                 : 
     344                 : /************************************************************************/
     345                 : /*                               GetFID()                               */
     346                 : /************************************************************************/
     347                 : 
     348             960 : const char* GMLExpatHandler::GetFID(void* attr)
     349                 : {
     350             960 :     const char** papszIter = (const char** )attr;
     351            1942 :     while(*papszIter)
     352                 :     {
     353             465 :         if (strcmp(*papszIter, "fid") == 0 ||
     354                 :             strcmp(*papszIter, "gml:id") == 0)
     355                 :         {
     356             443 :             return papszIter[1];
     357                 :         }
     358              22 :         papszIter += 2;
     359                 :     }
     360             517 :     return NULL;
     361                 : }
     362                 : 
     363                 : /************************************************************************/
     364                 : /*                        AddAttributes()                               */
     365                 : /************************************************************************/
     366                 : 
     367            7604 : CPLXMLNode* GMLExpatHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
     368                 : {
     369            7604 :     const char** papszIter = (const char** )attr;
     370                 : 
     371            7604 :     CPLXMLNode* psLastChild = NULL;
     372                 : 
     373           19581 :     while(*papszIter)
     374                 :     {
     375            4373 :         CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, papszIter[0]);
     376            4373 :         CPLCreateXMLNode(psChild, CXT_Text, papszIter[1]);
     377                 : 
     378            4373 :         if (psLastChild == NULL)
     379            3934 :             psNode->psChild = psChild;
     380                 :         else
     381             439 :             psLastChild->psNext = psChild;
     382            4373 :         psLastChild = psChild;
     383                 : 
     384            4373 :         papszIter += 2;
     385                 :     }
     386                 : 
     387            7604 :     return psLastChild;
     388                 : }
     389                 : 
     390                 : /************************************************************************/
     391                 : /*                    GetAttributeValue()                               */
     392                 : /************************************************************************/
     393                 : 
     394            5873 : char* GMLExpatHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
     395                 : {
     396            5873 :     const char** papszIter = (const char** )attr;
     397           11761 :     while(*papszIter)
     398                 :     {
     399              98 :         if (strcmp(*papszIter, pszAttributeName) == 0)
     400                 :         {
     401              83 :             return CPLStrdup(papszIter[1]);
     402                 :         }
     403              15 :         papszIter += 2;
     404                 :     }
     405            5790 :     return NULL;
     406                 : }
     407                 : 
     408                 : #endif
     409                 : 
     410                 : 
     411                 : static const char* const apszGMLGeometryElements[] =
     412                 : {
     413                 :     "CompositeSurface",
     414                 :     "Curve",
     415                 :     "GeometryCollection", /* OGR < 1.8.0 bug... */
     416                 :     "LineString",
     417                 :     "MultiCurve",
     418                 :     "MultiGeometry",
     419                 :     "MultiLineString",
     420                 :     "MultiPoint",
     421                 :     "MultiPolygon",
     422                 :     "MultiSurface",
     423                 :     "Point",
     424                 :     "Polygon",
     425                 :     "PolygonPatch",
     426                 :     "Solid",
     427                 :     "Surface",
     428                 :     "TopoCurve",
     429                 :     "TopoSurface"
     430                 : };
     431                 : 
     432                 : #define GML_GEOMETRY_TYPE_COUNT  \
     433                 :     (int)(sizeof(apszGMLGeometryElements) / sizeof(apszGMLGeometryElements[0]))
     434                 : 
     435                 : struct _GeometryNamesStruct {
     436                 :     unsigned long nHash;
     437                 :     const char   *pszName;
     438                 : } ;
     439                 : 
     440                 : /************************************************************************/
     441                 : /*                    GMLHandlerSortGeometryElements()                  */
     442                 : /************************************************************************/
     443                 : 
     444            5439 : static int GMLHandlerSortGeometryElements(const void *_pA, const void *_pB)
     445                 : {
     446            5439 :     GeometryNamesStruct* pA = (GeometryNamesStruct*)_pA;
     447            5439 :     GeometryNamesStruct* pB = (GeometryNamesStruct*)_pB;
     448            5439 :     CPLAssert(pA->nHash != pB->nHash);
     449            5439 :     if (pA->nHash < pB->nHash)
     450            2775 :         return -1;
     451                 :     else
     452            2664 :         return 1;
     453                 : }
     454                 : 
     455                 : /************************************************************************/
     456                 : /*                            GMLHandler()                              */
     457                 : /************************************************************************/
     458                 : 
     459             111 : GMLHandler::GMLHandler( GMLReader *poReader )
     460                 : 
     461                 : {
     462             111 :     m_poReader = poReader;
     463             111 :     m_bInCurField = FALSE;
     464             111 :     m_nCurFieldAlloc = 0;
     465             111 :     m_nCurFieldLen = 0;
     466             111 :     m_pszCurField = NULL;
     467             111 :     m_nAttributeIndex = -1;
     468             111 :     m_nAttributeDepth = 0;
     469                 : 
     470             111 :     m_pszGeometry = NULL;
     471             111 :     m_nGeomAlloc = 0;
     472             111 :     m_nGeomLen = 0;
     473             111 :     m_nGeometryDepth = 0;
     474                 : 
     475             111 :     m_nDepthFeature = m_nDepth = 0;
     476             111 :     m_inBoundedByDepth = 0;
     477             111 :     m_pszCityGMLGenericAttrName = NULL;
     478             111 :     m_inCityGMLGenericAttrDepth = 0;
     479             111 :     m_bIsCityGML = FALSE;
     480             111 :     m_bIsAIXM = FALSE;
     481             111 :     m_bReportHref = FALSE;
     482             111 :     m_pszHref = NULL;
     483             111 :     m_pszUom = NULL;
     484             111 :     m_pszValue = NULL;
     485                 : 
     486                 :     pasGeometryNames = (GeometryNamesStruct*)CPLMalloc(
     487             111 :         GML_GEOMETRY_TYPE_COUNT * sizeof(GeometryNamesStruct));
     488            1998 :     for(int i=0; i<GML_GEOMETRY_TYPE_COUNT; i++)
     489                 :     {
     490            1887 :         pasGeometryNames[i].pszName = apszGMLGeometryElements[i];
     491            1887 :         pasGeometryNames[i].nHash =
     492            1887 :                     CPLHashSetHashStr(pasGeometryNames[i].pszName);
     493                 :     }
     494                 :     qsort(pasGeometryNames, GML_GEOMETRY_TYPE_COUNT,
     495                 :           sizeof(GeometryNamesStruct),
     496             111 :           GMLHandlerSortGeometryElements);
     497                 : 
     498             111 :     nStackDepth = 0;
     499             111 :     stateStack[0] = STATE_TOP;
     500             111 : }
     501                 : 
     502                 : /************************************************************************/
     503                 : /*                            ~GMLHandler()                             */
     504                 : /************************************************************************/
     505                 : 
     506             111 : GMLHandler::~GMLHandler()
     507                 : 
     508                 : {
     509             111 :     if (apsXMLNode.size() >= 2 && apsXMLNode[1].psNode != NULL)
     510               1 :         CPLDestroyXMLNode(apsXMLNode[1].psNode);
     511                 : 
     512             111 :     CPLFree( m_pszCurField );
     513             111 :     CPLFree( m_pszGeometry );
     514             111 :     CPLFree( m_pszCityGMLGenericAttrName );
     515             111 :     CPLFree( m_pszHref );
     516             111 :     CPLFree( m_pszUom );
     517             111 :     CPLFree( m_pszValue );
     518             111 :     CPLFree( pasGeometryNames );
     519             111 : }
     520                 : 
     521                 : 
     522                 : /************************************************************************/
     523                 : /*                             startElement()                           */
     524                 : /************************************************************************/
     525                 : 
     526           14797 : OGRErr GMLHandler::startElement(const char *pszName, int nLenName, void* attr)
     527                 : {
     528                 :     OGRErr eRet;
     529           14797 :     switch(stateStack[nStackDepth])
     530                 :     {
     531             111 :         case STATE_TOP:                 eRet = startElementTop(pszName, nLenName, attr); break;
     532            1836 :         case STATE_DEFAULT:             eRet = startElementDefault(pszName, nLenName, attr); break;
     533            4218 :         case STATE_FEATURE:             eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
     534             495 :         case STATE_PROPERTY:            eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
     535            6658 :         case STATE_GEOMETRY:            eRet = startElementGeometry(pszName, nLenName, attr); break;
     536              64 :         case STATE_IGNORED_FEATURE:     eRet = OGRERR_NONE; break;
     537            1409 :         case STATE_BOUNDED_BY:          eRet = startElementBoundedBy(pszName, nLenName, attr); break;
     538               6 :         case STATE_CITYGML_ATTRIBUTE:   eRet = startElementCityGMLGenericAttr(pszName, nLenName, attr); break;
     539               0 :         default:                        eRet = OGRERR_NONE; break;
     540                 :     }
     541           14797 :     m_nDepth++;
     542           14797 :     return eRet;
     543                 : }
     544                 : 
     545                 : /************************************************************************/
     546                 : /*                              endElement()                            */
     547                 : /************************************************************************/
     548                 : 
     549           14790 : OGRErr GMLHandler::endElement()
     550                 : {
     551           14790 :     m_nDepth--;
     552           14790 :     switch(stateStack[nStackDepth])
     553                 :     {
     554               0 :         case STATE_TOP:                 return OGRERR_NONE; break;
     555             886 :         case STATE_DEFAULT:             return endElementDefault(); break;
     556            1447 :         case STATE_FEATURE:             return endElementFeature(); break;
     557            2905 :         case STATE_PROPERTY:            return endElementAttribute(); break;
     558            7601 :         case STATE_GEOMETRY:            return endElementGeometry(); break;
     559              76 :         case STATE_IGNORED_FEATURE:     return endElementIgnoredFeature(); break;
     560            1863 :         case STATE_BOUNDED_BY:          return endElementBoundedBy(); break;
     561              12 :         case STATE_CITYGML_ATTRIBUTE:   return endElementCityGMLGenericAttr(); break;
     562               0 :         default:                        return OGRERR_NONE; break;
     563                 :     }
     564                 : }
     565                 : 
     566                 : /************************************************************************/
     567                 : /*                              dataHandler()                           */
     568                 : /************************************************************************/
     569                 : 
     570           39489 : OGRErr GMLHandler::dataHandler(const char *data, int nLen)
     571                 : {
     572           39489 :     switch(stateStack[nStackDepth])
     573                 :     {
     574               0 :         case STATE_TOP:                 return OGRERR_NONE; break;
     575            3968 :         case STATE_DEFAULT:             return OGRERR_NONE; break;
     576            7370 :         case STATE_FEATURE:             return OGRERR_NONE; break;
     577            4077 :         case STATE_PROPERTY:            return dataHandlerAttribute(data, nLen); break;
     578           20618 :         case STATE_GEOMETRY:            return dataHandlerGeometry(data, nLen); break;
     579             140 :         case STATE_IGNORED_FEATURE:     return OGRERR_NONE; break;
     580            3286 :         case STATE_BOUNDED_BY:          return OGRERR_NONE; break;
     581              30 :         case STATE_CITYGML_ATTRIBUTE:   return dataHandlerAttribute(data, nLen); break;
     582               0 :         default:                        return OGRERR_NONE; break;
     583                 :     }
     584                 : }
     585                 : 
     586                 : #define PUSH_STATE(val) do { nStackDepth ++; CPLAssert(nStackDepth < STACK_SIZE); stateStack[nStackDepth] = val; } while(0)
     587                 : #define POP_STATE()     nStackDepth --
     588                 : 
     589                 : /************************************************************************/
     590                 : /*                       startElementBoundedBy()                        */
     591                 : /************************************************************************/
     592                 : 
     593            1409 : OGRErr GMLHandler::startElementBoundedBy(const char *pszName, int nLenName, void* attr )
     594                 : {
     595            1409 :     if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
     596                 :     {
     597              51 :         char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
     598              51 :         m_poReader->SetGlobalSRSName(pszGlobalSRSName);
     599              51 :         CPLFree(pszGlobalSRSName);
     600                 :     }
     601                 : 
     602            1409 :     return OGRERR_NONE;
     603                 : }
     604                 : 
     605                 : /************************************************************************/
     606                 : /*                       startElementGeometry()                         */
     607                 : /************************************************************************/
     608                 : 
     609            7604 : OGRErr GMLHandler::startElementGeometry(const char *pszName, int nLenName, void* attr )
     610                 : {
     611            7604 :     if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     612                 :     {
     613               0 :         m_inBoundedByDepth = m_nDepth;
     614                 : 
     615               0 :         PUSH_STATE(STATE_BOUNDED_BY);
     616                 : 
     617               0 :         return OGRERR_NONE;
     618                 :     }
     619                 : 
     620                 :     /* Create new XML Element */
     621            7604 :     CPLXMLNode* psCurNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
     622            7604 :     psCurNode->eType = CXT_Element;
     623            7604 :     psCurNode->pszValue = (char*) CPLMalloc( nLenName+1 );
     624            7604 :     memcpy(psCurNode->pszValue, pszName, nLenName+1);
     625                 : 
     626                 :     /* Attach element as the last child of its parent */
     627            7604 :     NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
     628            7604 :     CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
     629                 : 
     630            7604 :     if (psLastChildParent == NULL)
     631                 :     {
     632            3494 :         CPLXMLNode* psParent = sNodeLastChild.psNode;
     633            3494 :         if (psParent)
     634            2548 :             psParent->psChild = psCurNode;
     635                 :     }
     636                 :     else
     637                 :     {
     638            4110 :         psLastChildParent->psNext = psCurNode;
     639                 :     }
     640            7604 :     sNodeLastChild.psLastChild = psCurNode;
     641                 : 
     642                 :     /* Add attributes to the element */
     643            7604 :     CPLXMLNode* psLastChildCurNode = AddAttributes(psCurNode, attr);
     644                 : 
     645                 :     /* Some CityGML lack a srsDimension="3" in posList, such as in */
     646                 :     /* http://www.citygml.org/fileadmin/count.php?f=fileadmin%2Fcitygml%2Fdocs%2FFrankfurt_Street_Setting_LOD3.zip */
     647                 :     /* So we have to add it manually */
     648            7604 :     if (m_bIsCityGML && nLenName == 7 &&
     649                 :         strcmp(pszName, "posList") == 0 &&
     650                 :         CPLGetXMLValue(psCurNode, "srsDimension", NULL) == NULL)
     651                 :     {
     652               0 :         CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, "srsDimension");
     653               0 :         CPLCreateXMLNode(psChild, CXT_Text, "3");
     654                 : 
     655               0 :         if (psLastChildCurNode == NULL)
     656               0 :             psCurNode->psChild = psChild;
     657                 :         else
     658               0 :             psLastChildCurNode->psNext = psChild;
     659               0 :         psLastChildCurNode = psChild;
     660                 :     }
     661                 : 
     662                 :     /* Push the element on the stack */
     663                 :     NodeLastChild sNewNodeLastChild;
     664            7604 :     sNewNodeLastChild.psNode = psCurNode;
     665            7604 :     sNewNodeLastChild.psLastChild = psLastChildCurNode;
     666            7604 :     apsXMLNode.push_back(sNewNodeLastChild);
     667                 : 
     668            7604 :     if (m_pszGeometry)
     669                 :     {
     670               0 :         CPLFree(m_pszGeometry);
     671               0 :         m_pszGeometry = NULL;
     672               0 :         m_nGeomAlloc = 0;
     673               0 :         m_nGeomLen = 0;
     674                 :     }
     675                 : 
     676            7604 :     return OGRERR_NONE;
     677                 : }
     678                 : 
     679                 : /************************************************************************/
     680                 : /*                    startElementCityGMLGenericAttr()                  */
     681                 : /************************************************************************/
     682                 : 
     683               6 : OGRErr GMLHandler::startElementCityGMLGenericAttr(const char *pszName, int nLenName, void* attr )
     684                 : {
     685               6 :     if( strcmp(pszName, "value") == 0 )
     686                 :     {
     687               6 :         if(m_pszCurField)
     688                 :         {
     689               0 :             CPLFree(m_pszCurField);
     690               0 :             m_pszCurField = NULL;
     691               0 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     692                 :         }
     693               6 :         m_bInCurField = TRUE;
     694                 :     }
     695                 : 
     696               6 :     return OGRERR_NONE;
     697                 : }
     698                 : /************************************************************************/
     699                 : /*                      startElementFeatureAttribute()                  */
     700                 : /************************************************************************/
     701                 : 
     702            4713 : OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
     703                 : {
     704                 :     /* Reset flag */
     705            4713 :     m_bInCurField = FALSE;
     706                 : 
     707            4713 :     GMLReadState *poState = m_poReader->GetState();
     708                 : 
     709                 : /* -------------------------------------------------------------------- */
     710                 : /*      If we are collecting geometry, or if we determine this is a     */
     711                 : /*      geometry element then append to the geometry info.              */
     712                 : /* -------------------------------------------------------------------- */
     713            4713 :     if( IsGeometryElement( pszName ) )
     714                 :     {
     715                 :         int bReadGeometry;
     716                 : 
     717                 :         /* If the <GeometryElementPath> is defined in the .gfs, use it */
     718                 :         /* to read the appropriate geometry element */
     719             948 :         const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
     720             948 :         if (pszGeometryElement != NULL)
     721             336 :             bReadGeometry = strcmp(poState->osPath.c_str(), pszGeometryElement) == 0;
     722                 :         else
     723                 :         {
     724                 :             /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
     725                 :             /* not 'start' and 'end' geometries */
     726             612 :             if (m_bIsAIXM &&
     727                 :                 strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
     728               0 :                 bReadGeometry = strcmp( pszName, "Curve") == 0;
     729                 :             else
     730             612 :                 bReadGeometry = TRUE;
     731                 :         }
     732             948 :         if (bReadGeometry)
     733                 :         {
     734             946 :             m_nGeometryDepth = m_nDepth;
     735                 : 
     736             946 :             CPLAssert(apsXMLNode.size() == 0);
     737                 : 
     738                 :             NodeLastChild sNodeLastChild;
     739             946 :             sNodeLastChild.psNode = NULL;
     740             946 :             sNodeLastChild.psLastChild = NULL;
     741             946 :             apsXMLNode.push_back(sNodeLastChild);
     742                 : 
     743             946 :             PUSH_STATE(STATE_GEOMETRY);
     744                 : 
     745             946 :             return startElementGeometry(pszName, nLenName, attr);
     746                 :         }
     747                 :     }
     748                 : 
     749                 : 
     750            3765 :     else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     751                 :     {
     752             367 :         m_inBoundedByDepth = m_nDepth;
     753                 : 
     754             367 :         PUSH_STATE(STATE_BOUNDED_BY);
     755                 : 
     756             367 :         return OGRERR_NONE;
     757                 :     }
     758                 : 
     759                 : /* -------------------------------------------------------------------- */
     760                 : /*      Is it a CityGML generic attribute ?                             */
     761                 : /* -------------------------------------------------------------------- */
     762            3398 :     else if( m_bIsCityGML &&
     763                 :              m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
     764                 :     {
     765               6 :         CPLFree(m_pszCityGMLGenericAttrName);
     766               6 :         m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
     767               6 :         m_inCityGMLGenericAttrDepth = m_nDepth;
     768                 : 
     769               6 :         PUSH_STATE(STATE_CITYGML_ATTRIBUTE);
     770                 : 
     771               6 :         return OGRERR_NONE;
     772                 :     }
     773                 : 
     774                 : /* -------------------------------------------------------------------- */
     775                 : /*      If it is (or at least potentially is) a simple attribute,       */
     776                 : /*      then start collecting it.                                       */
     777                 : /* -------------------------------------------------------------------- */
     778            3392 :     else if( (m_nAttributeIndex =
     779                 :                 m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
     780                 :     {
     781            2905 :         if(m_pszCurField)
     782                 :         {
     783             347 :             CPLFree(m_pszCurField);
     784             347 :             m_pszCurField = NULL;
     785             347 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     786                 :         }
     787            2905 :         m_bInCurField = TRUE;
     788            2905 :         if (m_bReportHref)
     789                 :         {
     790               0 :             CPLFree(m_pszHref);
     791               0 :             m_pszHref = GetAttributeValue(attr, "xlink:href");
     792                 :         }
     793            2905 :         CPLFree(m_pszUom);
     794            2905 :         m_pszUom = GetAttributeValue(attr, "uom");
     795            2905 :         CPLFree(m_pszValue);
     796            2905 :         m_pszValue = GetAttributeValue(attr, "value");
     797                 : 
     798            2905 :         if (stateStack[nStackDepth] != STATE_PROPERTY)
     799                 :         {
     800            2877 :             m_nAttributeDepth = m_nDepth;
     801            2877 :             PUSH_STATE(STATE_PROPERTY);
     802                 :         }
     803                 : 
     804                 :     }
     805             487 :     else if( m_bReportHref && (m_nAttributeIndex =
     806                 :                 m_poReader->GetAttributeElementIndex( CPLSPrintf("%s_href", pszName ),
     807                 :                                                       nLenName + 5 )) != -1 )
     808                 :     {
     809               0 :         if(m_pszCurField)
     810                 :         {
     811               0 :             CPLFree(m_pszCurField);
     812               0 :             m_pszCurField = NULL;
     813               0 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     814                 :         }
     815               0 :         m_bInCurField = TRUE;
     816               0 :         CPLFree(m_pszHref);
     817               0 :         m_pszHref = GetAttributeValue(attr, "xlink:href");
     818                 : 
     819               0 :         if (stateStack[nStackDepth] != STATE_PROPERTY)
     820                 :         {
     821               0 :             m_nAttributeDepth = m_nDepth;
     822               0 :             PUSH_STATE(STATE_PROPERTY);
     823                 :         }
     824                 :     }
     825                 : 
     826            3394 :     poState->PushPath( pszName, nLenName );
     827                 : 
     828            3394 :     return OGRERR_NONE;
     829                 : }
     830                 : 
     831                 : /************************************************************************/
     832                 : /*                         startElementTop()                            */
     833                 : /************************************************************************/
     834                 : 
     835             111 : OGRErr GMLHandler::startElementTop(const char *pszName, int nLenName, void* attr )
     836                 : 
     837                 : {
     838             111 :     if (strcmp(pszName, "CityModel") == 0 )
     839                 :     {
     840               2 :         m_bIsCityGML = TRUE;
     841                 :     }
     842             109 :     else if (strcmp(pszName, "AIXMBasicMessage") == 0)
     843                 :     {
     844               0 :         m_bIsAIXM = m_bReportHref = TRUE;
     845                 :     }
     846                 : 
     847             111 :     stateStack[0] = STATE_DEFAULT;
     848                 : 
     849             111 :     return OGRERR_NONE;
     850                 : }
     851                 : 
     852                 : /************************************************************************/
     853                 : /*                        startElementDefault()                         */
     854                 : /************************************************************************/
     855                 : 
     856            1836 : OGRErr GMLHandler::startElementDefault(const char *pszName, int nLenName, void* attr )
     857                 : 
     858                 : {
     859                 : /* -------------------------------------------------------------------- */
     860                 : /*      Is it a feature?  If so push a whole new state, and return.     */
     861                 : /* -------------------------------------------------------------------- */
     862                 :     int nClassIndex;
     863            1836 :     if( (nClassIndex = m_poReader->GetFeatureElementIndex( pszName, nLenName )) != -1 )
     864                 :     {
     865             972 :         const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
     866             972 :         if ( pszFilteredClassName != NULL &&
     867                 :              strcmp(pszName, pszFilteredClassName) != 0 )
     868                 :         {
     869              12 :             m_nDepthFeature = m_nDepth;
     870                 : 
     871              12 :             PUSH_STATE(STATE_IGNORED_FEATURE);
     872                 : 
     873              12 :             return OGRERR_NONE;
     874                 :         }
     875                 :         else
     876                 :         {
     877             960 :             m_poReader->PushFeature( pszName, GetFID(attr), nClassIndex );
     878                 : 
     879             960 :             m_nDepthFeature = m_nDepth;
     880                 : 
     881             960 :             PUSH_STATE(STATE_FEATURE);
     882                 : 
     883             960 :             return OGRERR_NONE;
     884                 :         }
     885                 :     }
     886                 : 
     887             864 :     else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     888                 :     {
     889              87 :         m_inBoundedByDepth = m_nDepth;
     890                 : 
     891              87 :         PUSH_STATE(STATE_BOUNDED_BY);
     892                 : 
     893              87 :         return OGRERR_NONE;
     894                 :     }
     895                 : 
     896                 : /* -------------------------------------------------------------------- */
     897                 : /*      Push the element onto the current state's path.                 */
     898                 : /* -------------------------------------------------------------------- */
     899             777 :     m_poReader->GetState()->PushPath( pszName, nLenName );
     900                 : 
     901             777 :     return OGRERR_NONE;
     902                 : }
     903                 : 
     904                 : /************************************************************************/
     905                 : /*                      endElementIgnoredFeature()                      */
     906                 : /************************************************************************/
     907                 : 
     908              76 : OGRErr GMLHandler::endElementIgnoredFeature()
     909                 : 
     910                 : {
     911              76 :     if (m_nDepth == m_nDepthFeature)
     912                 :     {
     913              12 :         POP_STATE();
     914                 :     }
     915              76 :     return OGRERR_NONE;
     916                 : }
     917                 : 
     918                 : /************************************************************************/
     919                 : /*                         endElementBoundedBy()                        */
     920                 : /************************************************************************/
     921            1863 : OGRErr GMLHandler::endElementBoundedBy()
     922                 : 
     923                 : {
     924            1863 :     if( m_inBoundedByDepth == m_nDepth)
     925                 :     {
     926             454 :         POP_STATE();
     927                 :     }
     928                 : 
     929            1863 :     return OGRERR_NONE;
     930                 : }
     931                 : 
     932                 : /************************************************************************/
     933                 : /*                       ParseAIXMElevationPoint()                      */
     934                 : /************************************************************************/
     935                 : 
     936               0 : CPLXMLNode* GMLHandler::ParseAIXMElevationPoint(CPLXMLNode *psGML)
     937                 : {
     938                 :     const char* pszElevation =
     939               0 :         CPLGetXMLValue( psGML, "elevation", NULL );
     940               0 :     if (pszElevation)
     941                 :     {
     942                 :         m_poReader->SetFeaturePropertyDirectly( "elevation",
     943               0 :                                         CPLStrdup(pszElevation), -1 );
     944                 :         const char* pszElevationUnit =
     945               0 :             CPLGetXMLValue( psGML, "elevation.uom", NULL );
     946               0 :         if (pszElevationUnit)
     947                 :         {
     948                 :             m_poReader->SetFeaturePropertyDirectly( "elevation_uom",
     949               0 :                                             CPLStrdup(pszElevationUnit), -1 );
     950                 :         }
     951                 :     }
     952                 : 
     953                 :     const char* pszGeoidUndulation =
     954               0 :         CPLGetXMLValue( psGML, "geoidUndulation", NULL );
     955               0 :     if (pszGeoidUndulation)
     956                 :     {
     957                 :         m_poReader->SetFeaturePropertyDirectly( "geoidUndulation",
     958               0 :                                         CPLStrdup(pszGeoidUndulation), -1 );
     959                 :         const char* pszGeoidUndulationUnit =
     960               0 :             CPLGetXMLValue( psGML, "geoidUndulation.uom", NULL );
     961               0 :         if (pszGeoidUndulationUnit)
     962                 :         {
     963                 :             m_poReader->SetFeaturePropertyDirectly( "geoidUndulation_uom",
     964               0 :                                             CPLStrdup(pszGeoidUndulationUnit), -1 );
     965                 :         }
     966                 :     }
     967                 : 
     968                 :     const char* pszPos =
     969               0 :                     CPLGetXMLValue( psGML, "pos", NULL );
     970                 :     const char* pszCoordinates =
     971               0 :                 CPLGetXMLValue( psGML, "coordinates", NULL );
     972               0 :     if (pszPos != NULL)
     973                 :     {
     974                 :         char* pszGeometry = CPLStrdup(CPLSPrintf(
     975                 :             "<gml:Point><gml:pos>%s</gml:pos></gml:Point>",
     976               0 :                                                     pszPos));
     977               0 :         CPLDestroyXMLNode(psGML);
     978               0 :         psGML = CPLParseXMLString(pszGeometry);
     979               0 :         CPLFree(pszGeometry);
     980                 :     }
     981               0 :     else if (pszCoordinates != NULL)
     982                 :     {
     983                 :         char* pszGeometry = CPLStrdup(CPLSPrintf(
     984                 :             "<gml:Point><gml:coordinates>%s</gml:coordinates></gml:Point>",
     985               0 :                                             pszCoordinates));
     986               0 :         CPLDestroyXMLNode(psGML);
     987               0 :         psGML = CPLParseXMLString(pszGeometry);
     988               0 :         CPLFree(pszGeometry);
     989                 :     }
     990                 :     else
     991                 :     {
     992               0 :         CPLDestroyXMLNode(psGML);
     993               0 :         psGML = NULL;
     994                 :     }
     995                 : 
     996               0 :     return psGML;
     997                 : }
     998                 : 
     999                 : /************************************************************************/
    1000                 : /*                         endElementGeometry()                         */
    1001                 : /************************************************************************/
    1002            7601 : OGRErr GMLHandler::endElementGeometry()
    1003                 : 
    1004                 : {
    1005            7601 :     if (m_nGeomLen)
    1006                 :     {
    1007            1408 :         CPLXMLNode* psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
    1008            1408 :         psNode->eType = CXT_Text;
    1009            1408 :         psNode->pszValue = m_pszGeometry;
    1010                 : 
    1011            1408 :         NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
    1012            1408 :         CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
    1013            1408 :         if (psLastChildParent == NULL)
    1014                 :         {
    1015             677 :             CPLXMLNode* psParent = sNodeLastChild.psNode;
    1016             677 :             if (psParent)
    1017             677 :                 psParent->psChild = psNode;
    1018                 :         }
    1019                 :         else
    1020             731 :             psLastChildParent->psNext = psNode;
    1021            1408 :         sNodeLastChild.psLastChild = psNode;
    1022                 : 
    1023            1408 :         m_pszGeometry = NULL;
    1024            1408 :         m_nGeomAlloc = 0;
    1025            1408 :         m_nGeomLen = 0;
    1026                 :     }
    1027                 : 
    1028            7601 :     if( m_nDepth == m_nGeometryDepth )
    1029                 :     {
    1030             945 :         CPLXMLNode* psInterestNode = apsXMLNode[apsXMLNode.size()-1].psNode;
    1031                 : 
    1032                 :         /*char* pszXML = CPLSerializeXMLTree(psInterestNode);
    1033                 :         CPLDebug("GML", "geometry = %s", pszXML);
    1034                 :         CPLFree(pszXML);*/
    1035                 : 
    1036             945 :         apsXMLNode.pop_back();
    1037                 : 
    1038                 :         /* AIXM ElevatedPoint. We want to parse this */
    1039                 :         /* a bit specially because ElevatedPoint is aixm: stuff and */
    1040                 :         /* the srsDimension of the <gml:pos> can be set to TRUE although */
    1041                 :         /* they are only 2 coordinates in practice */
    1042             945 :         if ( m_bIsAIXM && psInterestNode != NULL &&
    1043                 :             strcmp(psInterestNode->pszValue, "ElevatedPoint") == 0 )
    1044                 :         {
    1045               0 :             psInterestNode = ParseAIXMElevationPoint(psInterestNode);
    1046                 :         }
    1047                 : 
    1048             945 :         if (m_poReader->FetchAllGeometries())
    1049               0 :             m_poReader->GetState()->m_poFeature->AddGeometry(psInterestNode);
    1050                 :         else
    1051             945 :             m_poReader->GetState()->m_poFeature->SetGeometryDirectly(psInterestNode);
    1052                 : 
    1053             945 :         POP_STATE();
    1054                 :     }
    1055                 : 
    1056            7601 :     apsXMLNode.pop_back();
    1057                 : 
    1058            7601 :     return OGRERR_NONE;
    1059                 : }
    1060                 : 
    1061                 : /************************************************************************/
    1062                 : /*                    endElementCityGMLGenericAttr()                    */
    1063                 : /************************************************************************/
    1064              12 : OGRErr GMLHandler::endElementCityGMLGenericAttr()
    1065                 : 
    1066                 : {
    1067              12 :     if( m_pszCityGMLGenericAttrName != NULL && m_bInCurField )
    1068                 :     {
    1069                 :         m_poReader->SetFeaturePropertyDirectly( m_pszCityGMLGenericAttrName,
    1070               6 :                                         m_pszCurField, -1 );
    1071               6 :         m_pszCurField = NULL;
    1072               6 :         m_nCurFieldLen = m_nCurFieldAlloc = 0;
    1073               6 :         m_bInCurField = FALSE;
    1074               6 :         CPLFree(m_pszCityGMLGenericAttrName);
    1075               6 :         m_pszCityGMLGenericAttrName = NULL;
    1076                 :     }
    1077                 : 
    1078              12 :     if( m_inCityGMLGenericAttrDepth == m_nDepth )
    1079                 :     {
    1080               6 :         POP_STATE();
    1081                 :     }
    1082                 : 
    1083              12 :     return OGRERR_NONE;
    1084                 : }
    1085                 : 
    1086                 : /************************************************************************/
    1087                 : /*                        endElementAttribute()                         */
    1088                 : /************************************************************************/
    1089            2905 : OGRErr GMLHandler::endElementAttribute()
    1090                 : 
    1091                 : {
    1092            2905 :     GMLReadState *poState = m_poReader->GetState();
    1093                 : 
    1094            2905 :     if (m_bInCurField)
    1095                 :     {
    1096            2429 :         if (m_pszCurField == NULL)
    1097                 :         {
    1098              12 :             if (m_pszValue != NULL)
    1099                 :             {
    1100                 :                 m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
    1101              10 :                                                 m_pszValue, -1 );
    1102              10 :                 m_pszValue = NULL;
    1103                 :             }
    1104                 :         }
    1105                 :         else
    1106                 :         {
    1107                 :             m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
    1108                 :                                             m_pszCurField,
    1109            2417 :                                             m_nAttributeIndex );
    1110            2417 :             m_pszCurField = NULL;
    1111                 :         }
    1112                 : 
    1113            2429 :         if (m_pszHref != NULL)
    1114                 :         {
    1115               0 :             CPLString osPropNameHref = poState->osPath + "_href";
    1116               0 :             m_poReader->SetFeaturePropertyDirectly( osPropNameHref, m_pszHref, -1 );
    1117               0 :             m_pszHref = NULL;
    1118                 :         }
    1119                 : 
    1120            2429 :         if (m_pszUom != NULL)
    1121                 :         {
    1122              10 :             CPLString osPropNameUom = poState->osPath + "_uom";
    1123              10 :             m_poReader->SetFeaturePropertyDirectly( osPropNameUom, m_pszUom, -1 );
    1124              10 :             m_pszUom = NULL;
    1125                 :         }
    1126                 : 
    1127            2429 :         m_nCurFieldLen = m_nCurFieldAlloc = 0;
    1128            2429 :         m_bInCurField = FALSE;
    1129            2429 :         m_nAttributeIndex = -1;
    1130                 : 
    1131            2429 :         CPLFree( m_pszValue );
    1132            2429 :         m_pszValue = NULL;
    1133                 :     }
    1134                 : 
    1135            2905 :     poState->PopPath();
    1136                 : 
    1137            2905 :     if( m_nAttributeDepth == m_nDepth )
    1138                 :     {
    1139            2877 :         POP_STATE();
    1140                 :     }
    1141                 : 
    1142            2905 :     return OGRERR_NONE;
    1143                 : }
    1144                 : 
    1145                 : /************************************************************************/
    1146                 : /*                          endElementFeature()                         */
    1147                 : /************************************************************************/
    1148            1447 : OGRErr GMLHandler::endElementFeature()
    1149                 : 
    1150                 : {
    1151                 : /* -------------------------------------------------------------------- */
    1152                 : /*      If we are collecting a feature, and this element tag matches    */
    1153                 : /*      element name for the class, then we have finished the           */
    1154                 : /*      feature, and we pop the feature read state.                     */
    1155                 : /* -------------------------------------------------------------------- */
    1156            1447 :     if( m_nDepth == m_nDepthFeature )
    1157                 :     {
    1158             959 :         m_poReader->PopState();
    1159                 : 
    1160             959 :         POP_STATE();
    1161                 :     }
    1162                 : 
    1163                 : /* -------------------------------------------------------------------- */
    1164                 : /*      Otherwise, we just pop the element off the local read states    */
    1165                 : /*      element stack.                                                  */
    1166                 : /* -------------------------------------------------------------------- */
    1167                 :     else
    1168                 :     {
    1169             488 :         m_poReader->GetState()->PopPath();
    1170                 :     }
    1171                 : 
    1172            1447 :     return OGRERR_NONE;
    1173                 : }
    1174                 : 
    1175                 : /************************************************************************/
    1176                 : /*                          endElementDefault()                         */
    1177                 : /************************************************************************/
    1178             886 : OGRErr GMLHandler::endElementDefault()
    1179                 : 
    1180                 : {
    1181             886 :     if (m_nDepth > 0)
    1182             776 :         m_poReader->GetState()->PopPath();
    1183                 : 
    1184             886 :     return OGRERR_NONE;
    1185                 : }
    1186                 : 
    1187                 : /************************************************************************/
    1188                 : /*                         dataHandlerAttribute()                       */
    1189                 : /************************************************************************/
    1190                 : 
    1191            4107 : OGRErr GMLHandler::dataHandlerAttribute(const char *data, int nLen)
    1192                 : 
    1193                 : {
    1194            4107 :     int nIter = 0;
    1195                 : 
    1196            4107 :     if( m_bInCurField )
    1197                 :     {
    1198                 :         // Ignore white space
    1199            3261 :         if (m_nCurFieldLen == 0)
    1200                 :         {
    1201            9820 :             while (nIter < nLen)
    1202                 :             {
    1203            5725 :                 char ch = data[nIter];
    1204            5725 :                 if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
    1205            2423 :                     break;
    1206            3302 :                 nIter ++;
    1207                 :             }
    1208                 :         }
    1209                 : 
    1210            3261 :         int nCharsLen = nLen - nIter;
    1211                 : 
    1212            3261 :         if (m_nCurFieldLen + nCharsLen + 1 > m_nCurFieldAlloc)
    1213                 :         {
    1214            2786 :             m_nCurFieldAlloc = m_nCurFieldAlloc * 4 / 3 + nCharsLen + 1;
    1215                 :             char *pszNewCurField = (char *)
    1216            2786 :                 VSIRealloc( m_pszCurField, m_nCurFieldAlloc );
    1217            2786 :             if (pszNewCurField == NULL)
    1218                 :             {
    1219               0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    1220                 :             }
    1221            2786 :             m_pszCurField = pszNewCurField;
    1222                 :         }
    1223            3261 :         memcpy( m_pszCurField + m_nCurFieldLen, data + nIter, nCharsLen);
    1224            3261 :         m_nCurFieldLen += nCharsLen;
    1225            3261 :         m_pszCurField[m_nCurFieldLen] = '\0';
    1226                 :     }
    1227                 : 
    1228            4107 :     return OGRERR_NONE;
    1229                 : }
    1230                 : 
    1231                 : /************************************************************************/
    1232                 : /*                         dataHandlerGeometry()                        */
    1233                 : /************************************************************************/
    1234                 : 
    1235           20618 : OGRErr GMLHandler::dataHandlerGeometry(const char *data, int nLen)
    1236                 : 
    1237                 : {
    1238           20618 :     int nIter = 0;
    1239                 : 
    1240                 :     // Ignore white space
    1241           20618 :     if (m_nGeomLen == 0)
    1242                 :     {
    1243          163426 :         while (nIter < nLen)
    1244                 :         {
    1245          123878 :             char ch = data[nIter];
    1246          123878 :             if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
    1247            1408 :                 break;
    1248          122470 :             nIter ++;
    1249                 :         }
    1250                 :     }
    1251                 : 
    1252           20618 :     int nCharsLen = nLen - nIter;
    1253           20618 :     if (nCharsLen)
    1254                 :     {
    1255            1548 :         if( m_nGeomLen + nCharsLen + 1 > m_nGeomAlloc )
    1256                 :         {
    1257            1507 :             m_nGeomAlloc = m_nGeomAlloc * 4 / 3 + nCharsLen + 1;
    1258                 :             char* pszNewGeometry = (char *)
    1259            1507 :                 VSIRealloc( m_pszGeometry, m_nGeomAlloc);
    1260            1507 :             if (pszNewGeometry == NULL)
    1261                 :             {
    1262               0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    1263                 :             }
    1264            1507 :             m_pszGeometry = pszNewGeometry;
    1265                 :         }
    1266            1548 :         memcpy( m_pszGeometry+m_nGeomLen, data + nIter, nCharsLen);
    1267            1548 :         m_nGeomLen += nCharsLen;
    1268            1548 :         m_pszGeometry[m_nGeomLen] = '\0';
    1269                 :     }
    1270                 : 
    1271           20618 :     return OGRERR_NONE;
    1272                 : }
    1273                 : 
    1274                 : 
    1275                 : /************************************************************************/
    1276                 : /*                         IsGeometryElement()                          */
    1277                 : /************************************************************************/
    1278                 : 
    1279            4713 : int GMLHandler::IsGeometryElement( const char *pszElement )
    1280                 : 
    1281                 : {
    1282            4713 :     int nFirst = 0;
    1283            4713 :     int nLast = GML_GEOMETRY_TYPE_COUNT- 1;
    1284            4713 :     unsigned long nHash = CPLHashSetHashStr(pszElement);
    1285           17576 :     do
    1286                 :     {
    1287           18524 :         int nMiddle = (nFirst + nLast) / 2;
    1288           18524 :         if (nHash == pasGeometryNames[nMiddle].nHash)
    1289             948 :             return strcmp(pszElement, pasGeometryNames[nMiddle].pszName) == 0;
    1290           17576 :         if (nHash < pasGeometryNames[nMiddle].nHash)
    1291           11000 :             nLast = nMiddle - 1;
    1292                 :         else
    1293            6576 :             nFirst = nMiddle + 1;
    1294                 :     } while(nFirst <= nLast);
    1295                 : 
    1296            3765 :     if (m_bIsAIXM && strcmp( pszElement, "ElevatedPoint") == 0)
    1297               0 :         return TRUE;
    1298                 : 
    1299            3765 :     return FALSE;
    1300                 : }

Generated by: LCOV version 1.7