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: 2012-04-28 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             246 : GMLExpatHandler::GMLExpatHandler( GMLReader *poReader, XML_Parser oParser ) : GMLHandler(poReader)
     253                 : 
     254                 : {
     255             246 :     m_oParser = oParser;
     256             246 :     m_bStopParsing = FALSE;
     257             246 :     m_nDataHandlerCounter = 0;
     258             246 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                           startElementCbk()                          */
     262                 : /************************************************************************/
     263                 : 
     264           52926 : void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszName,
     265                 :                                               const char **ppszAttr)
     266                 : 
     267                 : {
     268           52926 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     269           52926 :     if (pThis->m_bStopParsing)
     270               0 :         return;
     271                 : 
     272           52926 :     const char* pszIter = pszName;
     273                 :     char ch;
     274          712922 :     while((ch = *pszIter) != '\0')
     275                 :     {
     276          607070 :         if (ch == ':')
     277           36674 :             pszName = pszIter + 1;
     278          607070 :         pszIter ++;
     279                 :     }
     280                 : 
     281           52926 :     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           52862 : void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, const char* pszName )
     294                 : 
     295                 : {
     296           52862 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     297           52862 :     if (pThis->m_bStopParsing)
     298               0 :         return;
     299                 : 
     300           52862 :     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          157126 : void XMLCALL GMLExpatHandler::dataHandlerCbk(void *pUserData, const char *data, int nLen)
     313                 : 
     314                 : {
     315          157126 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     316          157126 :     if (pThis->m_bStopParsing)
     317               0 :         return;
     318                 : 
     319          157126 :     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          157126 :     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          157126 :     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            2826 : const char* GMLExpatHandler::GetFID(void* attr)
     349                 : {
     350            2826 :     const char** papszIter = (const char** )attr;
     351            5756 :     while(*papszIter)
     352                 :     {
     353            1084 :         if (strcmp(*papszIter, "fid") == 0 ||
     354                 :             strcmp(*papszIter, "gml:id") == 0)
     355                 :         {
     356             980 :             return papszIter[1];
     357                 :         }
     358             104 :         papszIter += 2;
     359                 :     }
     360            1846 :     return NULL;
     361                 : }
     362                 : 
     363                 : /************************************************************************/
     364                 : /*                        AddAttributes()                               */
     365                 : /************************************************************************/
     366                 : 
     367           33642 : CPLXMLNode* GMLExpatHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
     368                 : {
     369           33642 :     const char** papszIter = (const char** )attr;
     370                 : 
     371           33642 :     CPLXMLNode* psLastChild = NULL;
     372                 : 
     373           84852 :     while(*papszIter)
     374                 :     {
     375           17568 :         CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, papszIter[0]);
     376           17568 :         CPLCreateXMLNode(psChild, CXT_Text, papszIter[1]);
     377                 : 
     378           17568 :         if (psLastChild == NULL)
     379           16502 :             psNode->psChild = psChild;
     380                 :         else
     381            1066 :             psLastChild->psNext = psChild;
     382           17568 :         psLastChild = psChild;
     383                 : 
     384           17568 :         papszIter += 2;
     385                 :     }
     386                 : 
     387           33642 :     return psLastChild;
     388                 : }
     389                 : 
     390                 : /************************************************************************/
     391                 : /*                    GetAttributeValue()                               */
     392                 : /************************************************************************/
     393                 : 
     394           18840 : char* GMLExpatHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
     395                 : {
     396           18840 :     const char** papszIter = (const char** )attr;
     397           37704 :     while(*papszIter)
     398                 :     {
     399             204 :         if (strcmp(*papszIter, pszAttributeName) == 0)
     400                 :         {
     401             180 :             return CPLStrdup(papszIter[1]);
     402                 :         }
     403              24 :         papszIter += 2;
     404                 :     }
     405           18660 :     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           12054 : static int GMLHandlerSortGeometryElements(const void *_pA, const void *_pB)
     445                 : {
     446           12054 :     GeometryNamesStruct* pA = (GeometryNamesStruct*)_pA;
     447           12054 :     GeometryNamesStruct* pB = (GeometryNamesStruct*)_pB;
     448           12054 :     CPLAssert(pA->nHash != pB->nHash);
     449           12054 :     if (pA->nHash < pB->nHash)
     450            6150 :         return -1;
     451                 :     else
     452            5904 :         return 1;
     453                 : }
     454                 : 
     455                 : /************************************************************************/
     456                 : /*                            GMLHandler()                              */
     457                 : /************************************************************************/
     458                 : 
     459             246 : GMLHandler::GMLHandler( GMLReader *poReader )
     460                 : 
     461                 : {
     462             246 :     m_poReader = poReader;
     463             246 :     m_bInCurField = FALSE;
     464             246 :     m_nCurFieldAlloc = 0;
     465             246 :     m_nCurFieldLen = 0;
     466             246 :     m_pszCurField = NULL;
     467             246 :     m_nAttributeIndex = -1;
     468             246 :     m_nAttributeDepth = 0;
     469                 : 
     470             246 :     m_pszGeometry = NULL;
     471             246 :     m_nGeomAlloc = 0;
     472             246 :     m_nGeomLen = 0;
     473             246 :     m_nGeometryDepth = 0;
     474                 : 
     475             246 :     m_nDepthFeature = m_nDepth = 0;
     476             246 :     m_inBoundedByDepth = 0;
     477             246 :     m_pszCityGMLGenericAttrName = NULL;
     478             246 :     m_inCityGMLGenericAttrDepth = 0;
     479             246 :     m_bIsCityGML = FALSE;
     480             246 :     m_bIsAIXM = FALSE;
     481             246 :     m_bReportHref = FALSE;
     482             246 :     m_pszHref = NULL;
     483             246 :     m_pszUom = NULL;
     484             246 :     m_pszValue = NULL;
     485                 : 
     486                 :     pasGeometryNames = (GeometryNamesStruct*)CPLMalloc(
     487             246 :         GML_GEOMETRY_TYPE_COUNT * sizeof(GeometryNamesStruct));
     488            4428 :     for(int i=0; i<GML_GEOMETRY_TYPE_COUNT; i++)
     489                 :     {
     490            4182 :         pasGeometryNames[i].pszName = apszGMLGeometryElements[i];
     491            4182 :         pasGeometryNames[i].nHash =
     492            4182 :                     CPLHashSetHashStr(pasGeometryNames[i].pszName);
     493                 :     }
     494                 :     qsort(pasGeometryNames, GML_GEOMETRY_TYPE_COUNT,
     495                 :           sizeof(GeometryNamesStruct),
     496             246 :           GMLHandlerSortGeometryElements);
     497                 : 
     498             246 :     nStackDepth = 0;
     499             246 :     stateStack[0] = STATE_TOP;
     500             246 : }
     501                 : 
     502                 : /************************************************************************/
     503                 : /*                            ~GMLHandler()                             */
     504                 : /************************************************************************/
     505                 : 
     506             246 : GMLHandler::~GMLHandler()
     507                 : 
     508                 : {
     509             246 :     if (apsXMLNode.size() >= 2 && apsXMLNode[1].psNode != NULL)
     510               6 :         CPLDestroyXMLNode(apsXMLNode[1].psNode);
     511                 : 
     512             246 :     CPLFree( m_pszCurField );
     513             246 :     CPLFree( m_pszGeometry );
     514             246 :     CPLFree( m_pszCityGMLGenericAttrName );
     515             246 :     CPLFree( m_pszHref );
     516             246 :     CPLFree( m_pszUom );
     517             246 :     CPLFree( m_pszValue );
     518             246 :     CPLFree( pasGeometryNames );
     519             246 : }
     520                 : 
     521                 : 
     522                 : /************************************************************************/
     523                 : /*                             startElement()                           */
     524                 : /************************************************************************/
     525                 : 
     526           52926 : OGRErr GMLHandler::startElement(const char *pszName, int nLenName, void* attr)
     527                 : {
     528                 :     OGRErr eRet;
     529           52926 :     switch(stateStack[nStackDepth])
     530                 :     {
     531             246 :         case STATE_TOP:                 eRet = startElementTop(pszName, nLenName, attr); break;
     532            4712 :         case STATE_DEFAULT:             eRet = startElementDefault(pszName, nLenName, attr); break;
     533           12512 :         case STATE_FEATURE:             eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
     534            1498 :         case STATE_PROPERTY:            eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
     535           30848 :         case STATE_GEOMETRY:            eRet = startElementGeometry(pszName, nLenName, attr); break;
     536             128 :         case STATE_IGNORED_FEATURE:     eRet = OGRERR_NONE; break;
     537            2970 :         case STATE_BOUNDED_BY:          eRet = startElementBoundedBy(pszName, nLenName, attr); break;
     538              12 :         case STATE_CITYGML_ATTRIBUTE:   eRet = startElementCityGMLGenericAttr(pszName, nLenName, attr); break;
     539               0 :         default:                        eRet = OGRERR_NONE; break;
     540                 :     }
     541           52926 :     m_nDepth++;
     542           52926 :     return eRet;
     543                 : }
     544                 : 
     545                 : /************************************************************************/
     546                 : /*                              endElement()                            */
     547                 : /************************************************************************/
     548                 : 
     549           52862 : OGRErr GMLHandler::endElement()
     550                 : {
     551           52862 :     m_nDepth--;
     552           52862 :     switch(stateStack[nStackDepth])
     553                 :     {
     554               0 :         case STATE_TOP:                 return OGRERR_NONE; break;
     555            1912 :         case STATE_DEFAULT:             return endElementDefault(); break;
     556            3902 :         case STATE_FEATURE:             return endElementFeature(); break;
     557            9348 :         case STATE_PROPERTY:            return endElementAttribute(); break;
     558           33600 :         case STATE_GEOMETRY:            return endElementGeometry(); break;
     559             152 :         case STATE_IGNORED_FEATURE:     return endElementIgnoredFeature(); break;
     560            3924 :         case STATE_BOUNDED_BY:          return endElementBoundedBy(); break;
     561              24 :         case STATE_CITYGML_ATTRIBUTE:   return endElementCityGMLGenericAttr(); break;
     562               0 :         default:                        return OGRERR_NONE; break;
     563                 :     }
     564                 : }
     565                 : 
     566                 : /************************************************************************/
     567                 : /*                              dataHandler()                           */
     568                 : /************************************************************************/
     569                 : 
     570          157126 : OGRErr GMLHandler::dataHandler(const char *data, int nLen)
     571                 : {
     572          157126 :     switch(stateStack[nStackDepth])
     573                 :     {
     574               0 :         case STATE_TOP:                 return OGRERR_NONE; break;
     575           10100 :         case STATE_DEFAULT:             return OGRERR_NONE; break;
     576           22924 :         case STATE_FEATURE:             return OGRERR_NONE; break;
     577           13600 :         case STATE_PROPERTY:            return dataHandlerAttribute(data, nLen); break;
     578          103360 :         case STATE_GEOMETRY:            return dataHandlerGeometry(data, nLen); break;
     579             280 :         case STATE_IGNORED_FEATURE:     return OGRERR_NONE; break;
     580            6802 :         case STATE_BOUNDED_BY:          return OGRERR_NONE; break;
     581              60 :         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            2970 : OGRErr GMLHandler::startElementBoundedBy(const char *pszName, int nLenName, void* attr )
     594                 : {
     595            2970 :     if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
     596                 :     {
     597             116 :         char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
     598             116 :         m_poReader->SetGlobalSRSName(pszGlobalSRSName);
     599             116 :         CPLFree(pszGlobalSRSName);
     600                 :     }
     601                 : 
     602            2970 :     return OGRERR_NONE;
     603                 : }
     604                 : 
     605                 : /************************************************************************/
     606                 : /*                       startElementGeometry()                         */
     607                 : /************************************************************************/
     608                 : 
     609           33642 : OGRErr GMLHandler::startElementGeometry(const char *pszName, int nLenName, void* attr )
     610                 : {
     611           33642 :     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           33642 :     CPLXMLNode* psCurNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
     622           33642 :     psCurNode->eType = CXT_Element;
     623           33642 :     psCurNode->pszValue = (char*) CPLMalloc( nLenName+1 );
     624           33642 :     memcpy(psCurNode->pszValue, pszName, nLenName+1);
     625                 : 
     626                 :     /* Attach element as the last child of its parent */
     627           33642 :     NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
     628           33642 :     CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
     629                 : 
     630           33642 :     if (psLastChildParent == NULL)
     631                 :     {
     632           15796 :         CPLXMLNode* psParent = sNodeLastChild.psNode;
     633           15796 :         if (psParent)
     634           13002 :             psParent->psChild = psCurNode;
     635                 :     }
     636                 :     else
     637                 :     {
     638           17846 :         psLastChildParent->psNext = psCurNode;
     639                 :     }
     640           33642 :     sNodeLastChild.psLastChild = psCurNode;
     641                 : 
     642                 :     /* Add attributes to the element */
     643           33642 :     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           33642 :     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           33642 :     sNewNodeLastChild.psNode = psCurNode;
     665           33642 :     sNewNodeLastChild.psLastChild = psLastChildCurNode;
     666           33642 :     apsXMLNode.push_back(sNewNodeLastChild);
     667                 : 
     668           33642 :     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           33642 :     return OGRERR_NONE;
     677                 : }
     678                 : 
     679                 : /************************************************************************/
     680                 : /*                    startElementCityGMLGenericAttr()                  */
     681                 : /************************************************************************/
     682                 : 
     683              12 : OGRErr GMLHandler::startElementCityGMLGenericAttr(const char *pszName, int nLenName, void* attr )
     684                 : {
     685              12 :     if( strcmp(pszName, "value") == 0 )
     686                 :     {
     687              12 :         if(m_pszCurField)
     688                 :         {
     689               0 :             CPLFree(m_pszCurField);
     690               0 :             m_pszCurField = NULL;
     691               0 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     692                 :         }
     693              12 :         m_bInCurField = TRUE;
     694                 :     }
     695                 : 
     696              12 :     return OGRERR_NONE;
     697                 : }
     698                 : /************************************************************************/
     699                 : /*                      startElementFeatureAttribute()                  */
     700                 : /************************************************************************/
     701                 : 
     702           14010 : OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
     703                 : {
     704                 :     /* Reset flag */
     705           14010 :     m_bInCurField = FALSE;
     706                 : 
     707           14010 :     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           14010 :     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            2798 :         const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
     720            2798 :         if (pszGeometryElement != NULL)
     721             706 :             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            2092 :             if (m_bIsAIXM &&
     727                 :                 strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
     728               0 :                 bReadGeometry = strcmp( pszName, "Curve") == 0;
     729                 :             else
     730            2092 :                 bReadGeometry = TRUE;
     731                 :         }
     732            2798 :         if (bReadGeometry)
     733                 :         {
     734            2794 :             m_nGeometryDepth = m_nDepth;
     735                 : 
     736            2794 :             CPLAssert(apsXMLNode.size() == 0);
     737                 : 
     738                 :             NodeLastChild sNodeLastChild;
     739            2794 :             sNodeLastChild.psNode = NULL;
     740            2794 :             sNodeLastChild.psLastChild = NULL;
     741            2794 :             apsXMLNode.push_back(sNodeLastChild);
     742                 : 
     743            2794 :             PUSH_STATE(STATE_GEOMETRY);
     744                 : 
     745            2794 :             return startElementGeometry(pszName, nLenName, attr);
     746                 :         }
     747                 :     }
     748                 : 
     749                 : 
     750           11212 :     else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     751                 :     {
     752             770 :         m_inBoundedByDepth = m_nDepth;
     753                 : 
     754             770 :         PUSH_STATE(STATE_BOUNDED_BY);
     755                 : 
     756             770 :         return OGRERR_NONE;
     757                 :     }
     758                 : 
     759                 : /* -------------------------------------------------------------------- */
     760                 : /*      Is it a CityGML generic attribute ?                             */
     761                 : /* -------------------------------------------------------------------- */
     762           10442 :     else if( m_bIsCityGML &&
     763                 :              m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
     764                 :     {
     765              12 :         CPLFree(m_pszCityGMLGenericAttrName);
     766              12 :         m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
     767              12 :         m_inCityGMLGenericAttrDepth = m_nDepth;
     768                 : 
     769              12 :         PUSH_STATE(STATE_CITYGML_ATTRIBUTE);
     770                 : 
     771              12 :         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           10430 :     else if( (m_nAttributeIndex =
     779                 :                 m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
     780                 :     {
     781            9350 :         if(m_pszCurField)
     782                 :         {
     783            1188 :             CPLFree(m_pszCurField);
     784            1188 :             m_pszCurField = NULL;
     785            1188 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     786                 :         }
     787            9350 :         m_bInCurField = TRUE;
     788            9350 :         if (m_bReportHref)
     789                 :         {
     790               0 :             CPLFree(m_pszHref);
     791               0 :             m_pszHref = GetAttributeValue(attr, "xlink:href");
     792                 :         }
     793            9350 :         CPLFree(m_pszUom);
     794            9350 :         m_pszUom = GetAttributeValue(attr, "uom");
     795            9350 :         CPLFree(m_pszValue);
     796            9350 :         m_pszValue = GetAttributeValue(attr, "value");
     797                 : 
     798            9350 :         if (stateStack[nStackDepth] != STATE_PROPERTY)
     799                 :         {
     800            9294 :             m_nAttributeDepth = m_nDepth;
     801            9294 :             PUSH_STATE(STATE_PROPERTY);
     802                 :         }
     803                 : 
     804                 :     }
     805            1080 :     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           10434 :     poState->PushPath( pszName, nLenName );
     827                 : 
     828           10434 :     return OGRERR_NONE;
     829                 : }
     830                 : 
     831                 : /************************************************************************/
     832                 : /*                         startElementTop()                            */
     833                 : /************************************************************************/
     834                 : 
     835             246 : OGRErr GMLHandler::startElementTop(const char *pszName, int nLenName, void* attr )
     836                 : 
     837                 : {
     838             246 :     if (strcmp(pszName, "CityModel") == 0 )
     839                 :     {
     840               4 :         m_bIsCityGML = TRUE;
     841                 :     }
     842             242 :     else if (strcmp(pszName, "AIXMBasicMessage") == 0)
     843                 :     {
     844               0 :         m_bIsAIXM = m_bReportHref = TRUE;
     845                 :     }
     846                 : 
     847             246 :     stateStack[0] = STATE_DEFAULT;
     848                 : 
     849             246 :     return OGRERR_NONE;
     850                 : }
     851                 : 
     852                 : /************************************************************************/
     853                 : /*                        startElementDefault()                         */
     854                 : /************************************************************************/
     855                 : 
     856            4712 : 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            4712 :     if( (nClassIndex = m_poReader->GetFeatureElementIndex( pszName, nLenName )) != -1 )
     864                 :     {
     865            2850 :         const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
     866            2850 :         if ( pszFilteredClassName != NULL &&
     867                 :              strcmp(pszName, pszFilteredClassName) != 0 )
     868                 :         {
     869              24 :             m_nDepthFeature = m_nDepth;
     870                 : 
     871              24 :             PUSH_STATE(STATE_IGNORED_FEATURE);
     872                 : 
     873              24 :             return OGRERR_NONE;
     874                 :         }
     875                 :         else
     876                 :         {
     877            2826 :             m_poReader->PushFeature( pszName, GetFID(attr), nClassIndex );
     878                 : 
     879            2826 :             m_nDepthFeature = m_nDepth;
     880                 : 
     881            2826 :             PUSH_STATE(STATE_FEATURE);
     882                 : 
     883            2826 :             return OGRERR_NONE;
     884                 :         }
     885                 :     }
     886                 : 
     887            1862 :     else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     888                 :     {
     889             184 :         m_inBoundedByDepth = m_nDepth;
     890                 : 
     891             184 :         PUSH_STATE(STATE_BOUNDED_BY);
     892                 : 
     893             184 :         return OGRERR_NONE;
     894                 :     }
     895                 : 
     896                 : /* -------------------------------------------------------------------- */
     897                 : /*      Push the element onto the current state's path.                 */
     898                 : /* -------------------------------------------------------------------- */
     899            1678 :     m_poReader->GetState()->PushPath( pszName, nLenName );
     900                 : 
     901            1678 :     return OGRERR_NONE;
     902                 : }
     903                 : 
     904                 : /************************************************************************/
     905                 : /*                      endElementIgnoredFeature()                      */
     906                 : /************************************************************************/
     907                 : 
     908             152 : OGRErr GMLHandler::endElementIgnoredFeature()
     909                 : 
     910                 : {
     911             152 :     if (m_nDepth == m_nDepthFeature)
     912                 :     {
     913              24 :         POP_STATE();
     914                 :     }
     915             152 :     return OGRERR_NONE;
     916                 : }
     917                 : 
     918                 : /************************************************************************/
     919                 : /*                         endElementBoundedBy()                        */
     920                 : /************************************************************************/
     921            3924 : OGRErr GMLHandler::endElementBoundedBy()
     922                 : 
     923                 : {
     924            3924 :     if( m_inBoundedByDepth == m_nDepth)
     925                 :     {
     926             954 :         POP_STATE();
     927                 :     }
     928                 : 
     929            3924 :     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           33600 : OGRErr GMLHandler::endElementGeometry()
    1003                 : 
    1004                 : {
    1005           33600 :     if (m_nGeomLen)
    1006                 :     {
    1007            4696 :         CPLXMLNode* psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
    1008            4696 :         psNode->eType = CXT_Text;
    1009            4696 :         psNode->pszValue = m_pszGeometry;
    1010                 : 
    1011            4696 :         NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
    1012            4696 :         CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
    1013            4696 :         if (psLastChildParent == NULL)
    1014                 :         {
    1015            1636 :             CPLXMLNode* psParent = sNodeLastChild.psNode;
    1016            1636 :             if (psParent)
    1017            1636 :                 psParent->psChild = psNode;
    1018                 :         }
    1019                 :         else
    1020            3060 :             psLastChildParent->psNext = psNode;
    1021            4696 :         sNodeLastChild.psLastChild = psNode;
    1022                 : 
    1023            4696 :         m_pszGeometry = NULL;
    1024            4696 :         m_nGeomAlloc = 0;
    1025            4696 :         m_nGeomLen = 0;
    1026                 :     }
    1027                 : 
    1028           33600 :     if( m_nDepth == m_nGeometryDepth )
    1029                 :     {
    1030            2788 :         CPLXMLNode* psInterestNode = apsXMLNode[apsXMLNode.size()-1].psNode;
    1031                 : 
    1032                 :         /*char* pszXML = CPLSerializeXMLTree(psInterestNode);
    1033                 :         CPLDebug("GML", "geometry = %s", pszXML);
    1034                 :         CPLFree(pszXML);*/
    1035                 : 
    1036            2788 :         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            2788 :         if ( m_bIsAIXM && psInterestNode != NULL &&
    1043                 :             strcmp(psInterestNode->pszValue, "ElevatedPoint") == 0 )
    1044                 :         {
    1045               0 :             psInterestNode = ParseAIXMElevationPoint(psInterestNode);
    1046                 :         }
    1047                 : 
    1048            2788 :         if (m_poReader->FetchAllGeometries())
    1049               0 :             m_poReader->GetState()->m_poFeature->AddGeometry(psInterestNode);
    1050                 :         else
    1051            2788 :             m_poReader->GetState()->m_poFeature->SetGeometryDirectly(psInterestNode);
    1052                 : 
    1053            2788 :         POP_STATE();
    1054                 :     }
    1055                 : 
    1056           33600 :     apsXMLNode.pop_back();
    1057                 : 
    1058           33600 :     return OGRERR_NONE;
    1059                 : }
    1060                 : 
    1061                 : /************************************************************************/
    1062                 : /*                    endElementCityGMLGenericAttr()                    */
    1063                 : /************************************************************************/
    1064              24 : OGRErr GMLHandler::endElementCityGMLGenericAttr()
    1065                 : 
    1066                 : {
    1067              24 :     if( m_pszCityGMLGenericAttrName != NULL && m_bInCurField )
    1068                 :     {
    1069                 :         m_poReader->SetFeaturePropertyDirectly( m_pszCityGMLGenericAttrName,
    1070              12 :                                         m_pszCurField, -1 );
    1071              12 :         m_pszCurField = NULL;
    1072              12 :         m_nCurFieldLen = m_nCurFieldAlloc = 0;
    1073              12 :         m_bInCurField = FALSE;
    1074              12 :         CPLFree(m_pszCityGMLGenericAttrName);
    1075              12 :         m_pszCityGMLGenericAttrName = NULL;
    1076                 :     }
    1077                 : 
    1078              24 :     if( m_inCityGMLGenericAttrDepth == m_nDepth )
    1079                 :     {
    1080              12 :         POP_STATE();
    1081                 :     }
    1082                 : 
    1083              24 :     return OGRERR_NONE;
    1084                 : }
    1085                 : 
    1086                 : /************************************************************************/
    1087                 : /*                        endElementAttribute()                         */
    1088                 : /************************************************************************/
    1089            9348 : OGRErr GMLHandler::endElementAttribute()
    1090                 : 
    1091                 : {
    1092            9348 :     GMLReadState *poState = m_poReader->GetState();
    1093                 : 
    1094            9348 :     if (m_bInCurField)
    1095                 :     {
    1096            7890 :         if (m_pszCurField == NULL)
    1097                 :         {
    1098              84 :             if (m_pszValue != NULL)
    1099                 :             {
    1100                 :                 m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
    1101              20 :                                                 m_pszValue, -1 );
    1102              20 :                 m_pszValue = NULL;
    1103                 :             }
    1104                 :         }
    1105                 :         else
    1106                 :         {
    1107                 :             m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
    1108                 :                                             m_pszCurField,
    1109            7806 :                                             m_nAttributeIndex );
    1110            7806 :             m_pszCurField = NULL;
    1111                 :         }
    1112                 : 
    1113            7890 :         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            7890 :         if (m_pszUom != NULL)
    1121                 :         {
    1122              20 :             CPLString osPropNameUom = poState->osPath + "_uom";
    1123              20 :             m_poReader->SetFeaturePropertyDirectly( osPropNameUom, m_pszUom, -1 );
    1124              20 :             m_pszUom = NULL;
    1125                 :         }
    1126                 : 
    1127            7890 :         m_nCurFieldLen = m_nCurFieldAlloc = 0;
    1128            7890 :         m_bInCurField = FALSE;
    1129            7890 :         m_nAttributeIndex = -1;
    1130                 : 
    1131            7890 :         CPLFree( m_pszValue );
    1132            7890 :         m_pszValue = NULL;
    1133                 :     }
    1134                 : 
    1135            9348 :     poState->PopPath();
    1136                 : 
    1137            9348 :     if( m_nAttributeDepth == m_nDepth )
    1138                 :     {
    1139            9292 :         POP_STATE();
    1140                 :     }
    1141                 : 
    1142            9348 :     return OGRERR_NONE;
    1143                 : }
    1144                 : 
    1145                 : /************************************************************************/
    1146                 : /*                          endElementFeature()                         */
    1147                 : /************************************************************************/
    1148            3902 : 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            3902 :     if( m_nDepth == m_nDepthFeature )
    1157                 :     {
    1158            2820 :         m_poReader->PopState();
    1159                 : 
    1160            2820 :         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            1082 :         m_poReader->GetState()->PopPath();
    1170                 :     }
    1171                 : 
    1172            3902 :     return OGRERR_NONE;
    1173                 : }
    1174                 : 
    1175                 : /************************************************************************/
    1176                 : /*                          endElementDefault()                         */
    1177                 : /************************************************************************/
    1178            1912 : OGRErr GMLHandler::endElementDefault()
    1179                 : 
    1180                 : {
    1181            1912 :     if (m_nDepth > 0)
    1182            1672 :         m_poReader->GetState()->PopPath();
    1183                 : 
    1184            1912 :     return OGRERR_NONE;
    1185                 : }
    1186                 : 
    1187                 : /************************************************************************/
    1188                 : /*                         dataHandlerAttribute()                       */
    1189                 : /************************************************************************/
    1190                 : 
    1191           13660 : OGRErr GMLHandler::dataHandlerAttribute(const char *data, int nLen)
    1192                 : 
    1193                 : {
    1194           13660 :     int nIter = 0;
    1195                 : 
    1196           13660 :     if( m_bInCurField )
    1197                 :     {
    1198                 :         // Ignore white space
    1199           10814 :         if (m_nCurFieldLen == 0)
    1200                 :         {
    1201           33100 :             while (nIter < nLen)
    1202                 :             {
    1203           19298 :                 char ch = data[nIter];
    1204           19298 :                 if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
    1205            7818 :                     break;
    1206           11480 :                 nIter ++;
    1207                 :             }
    1208                 :         }
    1209                 : 
    1210           10814 :         int nCharsLen = nLen - nIter;
    1211                 : 
    1212           10814 :         if (m_nCurFieldLen + nCharsLen + 1 > m_nCurFieldAlloc)
    1213                 :         {
    1214            9052 :             m_nCurFieldAlloc = m_nCurFieldAlloc * 4 / 3 + nCharsLen + 1;
    1215                 :             char *pszNewCurField = (char *)
    1216            9052 :                 VSIRealloc( m_pszCurField, m_nCurFieldAlloc );
    1217            9052 :             if (pszNewCurField == NULL)
    1218                 :             {
    1219               0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    1220                 :             }
    1221            9052 :             m_pszCurField = pszNewCurField;
    1222                 :         }
    1223           10814 :         memcpy( m_pszCurField + m_nCurFieldLen, data + nIter, nCharsLen);
    1224           10814 :         m_nCurFieldLen += nCharsLen;
    1225           10814 :         m_pszCurField[m_nCurFieldLen] = '\0';
    1226                 :     }
    1227                 : 
    1228           13660 :     return OGRERR_NONE;
    1229                 : }
    1230                 : 
    1231                 : /************************************************************************/
    1232                 : /*                         dataHandlerGeometry()                        */
    1233                 : /************************************************************************/
    1234                 : 
    1235          103360 : OGRErr GMLHandler::dataHandlerGeometry(const char *data, int nLen)
    1236                 : 
    1237                 : {
    1238          103360 :     int nIter = 0;
    1239                 : 
    1240                 :     // Ignore white space
    1241          103360 :     if (m_nGeomLen == 0)
    1242                 :     {
    1243          890472 :         while (nIter < nLen)
    1244                 :         {
    1245          689008 :             char ch = data[nIter];
    1246          689008 :             if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
    1247            4696 :                 break;
    1248          684312 :             nIter ++;
    1249                 :         }
    1250                 :     }
    1251                 : 
    1252          103360 :     int nCharsLen = nLen - nIter;
    1253          103360 :     if (nCharsLen)
    1254                 :     {
    1255            4976 :         if( m_nGeomLen + nCharsLen + 1 > m_nGeomAlloc )
    1256                 :         {
    1257            4894 :             m_nGeomAlloc = m_nGeomAlloc * 4 / 3 + nCharsLen + 1;
    1258                 :             char* pszNewGeometry = (char *)
    1259            4894 :                 VSIRealloc( m_pszGeometry, m_nGeomAlloc);
    1260            4894 :             if (pszNewGeometry == NULL)
    1261                 :             {
    1262               0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    1263                 :             }
    1264            4894 :             m_pszGeometry = pszNewGeometry;
    1265                 :         }
    1266            4976 :         memcpy( m_pszGeometry+m_nGeomLen, data + nIter, nCharsLen);
    1267            4976 :         m_nGeomLen += nCharsLen;
    1268            4976 :         m_pszGeometry[m_nGeomLen] = '\0';
    1269                 :     }
    1270                 : 
    1271          103360 :     return OGRERR_NONE;
    1272                 : }
    1273                 : 
    1274                 : 
    1275                 : /************************************************************************/
    1276                 : /*                         IsGeometryElement()                          */
    1277                 : /************************************************************************/
    1278                 : 
    1279           14010 : int GMLHandler::IsGeometryElement( const char *pszElement )
    1280                 : 
    1281                 : {
    1282           14010 :     int nFirst = 0;
    1283           14010 :     int nLast = GML_GEOMETRY_TYPE_COUNT- 1;
    1284           14010 :     unsigned long nHash = CPLHashSetHashStr(pszElement);
    1285           53250 :     do
    1286                 :     {
    1287           56048 :         int nMiddle = (nFirst + nLast) / 2;
    1288           56048 :         if (nHash == pasGeometryNames[nMiddle].nHash)
    1289            2798 :             return strcmp(pszElement, pasGeometryNames[nMiddle].pszName) == 0;
    1290           53250 :         if (nHash < pasGeometryNames[nMiddle].nHash)
    1291           32180 :             nLast = nMiddle - 1;
    1292                 :         else
    1293           21070 :             nFirst = nMiddle + 1;
    1294                 :     } while(nFirst <= nLast);
    1295                 : 
    1296           11212 :     if (m_bIsAIXM && strcmp( pszElement, "ElevatedPoint") == 0)
    1297               0 :         return TRUE;
    1298                 : 
    1299           11212 :     return FALSE;
    1300                 : }

Generated by: LCOV version 1.7