LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - gmlhandler.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 537 355 66.1 %
Date: 2012-12-26 Functions: 44 28 63.6 %

       1                 : /**********************************************************************
       2                 :  * $Id: gmlhandler.cpp 25183 2012-10-27 18:09:53Z 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 at line %d, column %d\n", 
     139               0 :               pszErrorMessage, (int)exception.getLineNumber(), (int)exception.getColumnNumber() );
     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             200 : GMLExpatHandler::GMLExpatHandler( GMLReader *poReader, XML_Parser oParser ) : GMLHandler(poReader)
     253                 : 
     254                 : {
     255             200 :     m_oParser = oParser;
     256             200 :     m_bStopParsing = FALSE;
     257             200 :     m_nDataHandlerCounter = 0;
     258             200 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                           startElementCbk()                          */
     262                 : /************************************************************************/
     263                 : 
     264           52227 : void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszName,
     265                 :                                               const char **ppszAttr)
     266                 : 
     267                 : {
     268           52227 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     269           52227 :     if (pThis->m_bStopParsing)
     270               0 :         return;
     271                 : 
     272           52227 :     const char* pszIter = pszName;
     273                 :     char ch;
     274          730670 :     while((ch = *pszIter) != '\0')
     275                 :     {
     276          626216 :         if (ch == ':')
     277           43968 :             pszName = pszIter + 1;
     278          626216 :         pszIter ++;
     279                 :     }
     280                 : 
     281           52227 :     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           52173 : void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, const char* pszName )
     294                 : 
     295                 : {
     296           52173 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     297           52173 :     if (pThis->m_bStopParsing)
     298               0 :         return;
     299                 : 
     300           52173 :     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          151474 : void XMLCALL GMLExpatHandler::dataHandlerCbk(void *pUserData, const char *data, int nLen)
     313                 : 
     314                 : {
     315          151474 :     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     316          151474 :     if (pThis->m_bStopParsing)
     317               0 :         return;
     318                 : 
     319          151474 :     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          151474 :     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          151474 :     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            2508 : const char* GMLExpatHandler::GetFID(void* attr)
     349                 : {
     350            2508 :     const char** papszIter = (const char** )attr;
     351            6478 :     while(*papszIter)
     352                 :     {
     353            3053 :         if (strcmp(*papszIter, "fid") == 0 ||
     354                 :             strcmp(*papszIter, "gml:id") == 0)
     355                 :         {
     356            1591 :             return papszIter[1];
     357                 :         }
     358            1462 :         papszIter += 2;
     359                 :     }
     360             917 :     return NULL;
     361                 : }
     362                 : 
     363                 : /************************************************************************/
     364                 : /*                        AddAttributes()                               */
     365                 : /************************************************************************/
     366                 : 
     367           23174 : CPLXMLNode* GMLExpatHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
     368                 : {
     369           23174 :     const char** papszIter = (const char** )attr;
     370                 : 
     371           23174 :     CPLXMLNode* psLastChild = NULL;
     372                 : 
     373           58703 :     while(*papszIter)
     374                 :     {
     375           12355 :         CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, papszIter[0]);
     376           12355 :         CPLCreateXMLNode(psChild, CXT_Text, papszIter[1]);
     377                 : 
     378           12355 :         if (psLastChild == NULL)
     379           10065 :             psNode->psChild = psChild;
     380                 :         else
     381            2290 :             psLastChild->psNext = psChild;
     382           12355 :         psLastChild = psChild;
     383                 : 
     384           12355 :         papszIter += 2;
     385                 :     }
     386                 : 
     387           23174 :     return psLastChild;
     388                 : }
     389                 : 
     390                 : /************************************************************************/
     391                 : /*                    GetAttributeValue()                               */
     392                 : /************************************************************************/
     393                 : 
     394           33307 : char* GMLExpatHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
     395                 : {
     396           33307 :     const char** papszIter = (const char** )attr;
     397           66628 :     while(*papszIter)
     398                 :     {
     399             149 :         if (strcmp(*papszIter, pszAttributeName) == 0)
     400                 :         {
     401             135 :             return CPLStrdup(papszIter[1]);
     402                 :         }
     403              14 :         papszIter += 2;
     404                 :     }
     405           33172 :     return NULL;
     406                 : }
     407                 : 
     408                 : #endif
     409                 : 
     410                 : 
     411                 : static const char* const apszGMLGeometryElements[] =
     412                 : {
     413                 :     "CompositeCurve",
     414                 :     "CompositeSurface",
     415                 :     "Curve",
     416                 :     "GeometryCollection", /* OGR < 1.8.0 bug... */
     417                 :     "LineString",
     418                 :     "MultiCurve",
     419                 :     "MultiGeometry",
     420                 :     "MultiLineString",
     421                 :     "MultiPoint",
     422                 :     "MultiPolygon",
     423                 :     "MultiSurface",
     424                 :     "Point",
     425                 :     "Polygon",
     426                 :     "PolygonPatch",
     427                 :     "SimplePolygon", /* GML 3.3 compact encoding */
     428                 :     "SimpleRectangle", /* GML 3.3 compact encoding */
     429                 :     "SimpleTriangle", /* GML 3.3 compact encoding */
     430                 :     "SimpleMultiPoint", /* GML 3.3 compact encoding */
     431                 :     "Solid",
     432                 :     "Surface",
     433                 :     "TopoCurve",
     434                 :     "TopoSurface"
     435                 : };
     436                 : 
     437                 : #define GML_GEOMETRY_TYPE_COUNT  \
     438                 :     (int)(sizeof(apszGMLGeometryElements) / sizeof(apszGMLGeometryElements[0]))
     439                 : 
     440                 : struct _GeometryNamesStruct {
     441                 :     unsigned long nHash;
     442                 :     const char   *pszName;
     443                 : } ;
     444                 : 
     445                 : /************************************************************************/
     446                 : /*                    GMLHandlerSortGeometryElements()                  */
     447                 : /************************************************************************/
     448                 : 
     449           14800 : static int GMLHandlerSortGeometryElements(const void *_pA, const void *_pB)
     450                 : {
     451           14800 :     GeometryNamesStruct* pA = (GeometryNamesStruct*)_pA;
     452           14800 :     GeometryNamesStruct* pB = (GeometryNamesStruct*)_pB;
     453           14800 :     CPLAssert(pA->nHash != pB->nHash);
     454           14800 :     if (pA->nHash < pB->nHash)
     455            6800 :         return -1;
     456                 :     else
     457            8000 :         return 1;
     458                 : }
     459                 : 
     460                 : /************************************************************************/
     461                 : /*                            GMLHandler()                              */
     462                 : /************************************************************************/
     463                 : 
     464             200 : GMLHandler::GMLHandler( GMLReader *poReader )
     465                 : 
     466                 : {
     467             200 :     m_poReader = poReader;
     468             200 :     m_bInCurField = FALSE;
     469             200 :     m_nCurFieldAlloc = 0;
     470             200 :     m_nCurFieldLen = 0;
     471             200 :     m_pszCurField = NULL;
     472             200 :     m_nAttributeIndex = -1;
     473             200 :     m_nAttributeDepth = 0;
     474                 : 
     475             200 :     m_pszGeometry = NULL;
     476             200 :     m_nGeomAlloc = 0;
     477             200 :     m_nGeomLen = 0;
     478             200 :     m_nGeometryDepth = 0;
     479             200 :     m_bAlreadyFoundGeometry = FALSE;
     480                 : 
     481             200 :     m_nDepthFeature = m_nDepth = 0;
     482             200 :     m_inBoundedByDepth = 0;
     483             200 :     m_pszCityGMLGenericAttrName = NULL;
     484             200 :     m_inCityGMLGenericAttrDepth = 0;
     485             200 :     m_bIsCityGML = FALSE;
     486             200 :     m_bIsAIXM = FALSE;
     487             200 :     m_bReportHref = FALSE;
     488             200 :     m_pszHref = NULL;
     489             200 :     m_pszUom = NULL;
     490             200 :     m_pszValue = NULL;
     491                 : 
     492                 :     pasGeometryNames = (GeometryNamesStruct*)CPLMalloc(
     493             200 :         GML_GEOMETRY_TYPE_COUNT * sizeof(GeometryNamesStruct));
     494            4600 :     for(int i=0; i<GML_GEOMETRY_TYPE_COUNT; i++)
     495                 :     {
     496            4400 :         pasGeometryNames[i].pszName = apszGMLGeometryElements[i];
     497            4400 :         pasGeometryNames[i].nHash =
     498            4400 :                     CPLHashSetHashStr(pasGeometryNames[i].pszName);
     499                 :     }
     500                 :     qsort(pasGeometryNames, GML_GEOMETRY_TYPE_COUNT,
     501                 :           sizeof(GeometryNamesStruct),
     502             200 :           GMLHandlerSortGeometryElements);
     503                 : 
     504             200 :     nStackDepth = 0;
     505             200 :     stateStack[0] = STATE_TOP;
     506             200 : }
     507                 : 
     508                 : /************************************************************************/
     509                 : /*                            ~GMLHandler()                             */
     510                 : /************************************************************************/
     511                 : 
     512             200 : GMLHandler::~GMLHandler()
     513                 : 
     514                 : {
     515             200 :     if (apsXMLNode.size() >= 2 && apsXMLNode[1].psNode != NULL)
     516               6 :         CPLDestroyXMLNode(apsXMLNode[1].psNode);
     517                 : 
     518             200 :     CPLFree( m_pszCurField );
     519             200 :     CPLFree( m_pszGeometry );
     520             200 :     CPLFree( m_pszCityGMLGenericAttrName );
     521             200 :     CPLFree( m_pszHref );
     522             200 :     CPLFree( m_pszUom );
     523             200 :     CPLFree( m_pszValue );
     524             200 :     CPLFree( pasGeometryNames );
     525             200 : }
     526                 : 
     527                 : 
     528                 : /************************************************************************/
     529                 : /*                             startElement()                           */
     530                 : /************************************************************************/
     531                 : 
     532           52227 : OGRErr GMLHandler::startElement(const char *pszName, int nLenName, void* attr)
     533                 : {
     534                 :     OGRErr eRet;
     535           52227 :     switch(stateStack[nStackDepth])
     536                 :     {
     537             200 :         case STATE_TOP:                 eRet = startElementTop(pszName, nLenName, attr); break;
     538            6905 :         case STATE_DEFAULT:             eRet = startElementDefault(pszName, nLenName, attr); break;
     539           20917 :         case STATE_FEATURE:             eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
     540             727 :         case STATE_PROPERTY:            eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
     541           20686 :         case STATE_GEOMETRY:            eRet = startElementGeometry(pszName, nLenName, attr); break;
     542               0 :         case STATE_IGNORED_FEATURE:     eRet = OGRERR_NONE; break;
     543            2786 :         case STATE_BOUNDED_BY:          eRet = startElementBoundedBy(pszName, nLenName, attr); break;
     544               6 :         case STATE_CITYGML_ATTRIBUTE:   eRet = startElementCityGMLGenericAttr(pszName, nLenName, attr); break;
     545               0 :         default:                        eRet = OGRERR_NONE; break;
     546                 :     }
     547           52227 :     m_nDepth++;
     548           52227 :     return eRet;
     549                 : }
     550                 : 
     551                 : /************************************************************************/
     552                 : /*                              endElement()                            */
     553                 : /************************************************************************/
     554                 : 
     555           52173 : OGRErr GMLHandler::endElement()
     556                 : {
     557           52173 :     m_nDepth--;
     558           52173 :     switch(stateStack[nStackDepth])
     559                 :     {
     560               0 :         case STATE_TOP:                 return OGRERR_NONE; break;
     561            4422 :         case STATE_DEFAULT:             return endElementDefault(); break;
     562            4311 :         case STATE_FEATURE:             return endElementFeature(); break;
     563           16595 :         case STATE_PROPERTY:            return endElementAttribute(); break;
     564           23143 :         case STATE_GEOMETRY:            return endElementGeometry(); break;
     565               0 :         case STATE_IGNORED_FEATURE:     return endElementIgnoredFeature(); break;
     566            3690 :         case STATE_BOUNDED_BY:          return endElementBoundedBy(); break;
     567              12 :         case STATE_CITYGML_ATTRIBUTE:   return endElementCityGMLGenericAttr(); break;
     568               0 :         default:                        return OGRERR_NONE; break;
     569                 :     }
     570                 : }
     571                 : 
     572                 : /************************************************************************/
     573                 : /*                              dataHandler()                           */
     574                 : /************************************************************************/
     575                 : 
     576          151474 : OGRErr GMLHandler::dataHandler(const char *data, int nLen)
     577                 : {
     578          151474 :     switch(stateStack[nStackDepth])
     579                 :     {
     580               0 :         case STATE_TOP:                 return OGRERR_NONE; break;
     581           17714 :         case STATE_DEFAULT:             return OGRERR_NONE; break;
     582           39750 :         case STATE_FEATURE:             return OGRERR_NONE; break;
     583           18130 :         case STATE_PROPERTY:            return dataHandlerAttribute(data, nLen); break;
     584           71696 :         case STATE_GEOMETRY:            return dataHandlerGeometry(data, nLen); break;
     585               0 :         case STATE_IGNORED_FEATURE:     return OGRERR_NONE; break;
     586            4154 :         case STATE_BOUNDED_BY:          return OGRERR_NONE; break;
     587              30 :         case STATE_CITYGML_ATTRIBUTE:   return dataHandlerAttribute(data, nLen); break;
     588               0 :         default:                        return OGRERR_NONE; break;
     589                 :     }
     590                 : }
     591                 : 
     592                 : #define PUSH_STATE(val) do { nStackDepth ++; CPLAssert(nStackDepth < STACK_SIZE); stateStack[nStackDepth] = val; } while(0)
     593                 : #define POP_STATE()     nStackDepth --
     594                 : 
     595                 : /************************************************************************/
     596                 : /*                       startElementBoundedBy()                        */
     597                 : /************************************************************************/
     598                 : 
     599            2786 : OGRErr GMLHandler::startElementBoundedBy(const char *pszName, int nLenName, void* attr )
     600                 : {
     601            2786 :     if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
     602                 :     {
     603             107 :         char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
     604             107 :         m_poReader->SetGlobalSRSName(pszGlobalSRSName);
     605             107 :         CPLFree(pszGlobalSRSName);
     606                 :     }
     607                 : 
     608            2786 :     return OGRERR_NONE;
     609                 : }
     610                 : 
     611                 : /************************************************************************/
     612                 : /*                       startElementGeometry()                         */
     613                 : /************************************************************************/
     614                 : 
     615           23174 : OGRErr GMLHandler::startElementGeometry(const char *pszName, int nLenName, void* attr )
     616                 : {
     617           23174 :     if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     618                 :     {
     619               0 :         m_inBoundedByDepth = m_nDepth;
     620                 : 
     621               0 :         PUSH_STATE(STATE_BOUNDED_BY);
     622                 : 
     623               0 :         return OGRERR_NONE;
     624                 :     }
     625                 : 
     626                 :     /* Create new XML Element */
     627           23174 :     CPLXMLNode* psCurNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
     628           23174 :     psCurNode->eType = CXT_Element;
     629           23174 :     psCurNode->pszValue = (char*) CPLMalloc( nLenName+1 );
     630           23174 :     memcpy(psCurNode->pszValue, pszName, nLenName+1);
     631                 : 
     632                 :     /* Attach element as the last child of its parent */
     633           23174 :     NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
     634           23174 :     CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
     635                 : 
     636           23174 :     if (psLastChildParent == NULL)
     637                 :     {
     638           12030 :         CPLXMLNode* psParent = sNodeLastChild.psNode;
     639           12030 :         if (psParent)
     640            9542 :             psParent->psChild = psCurNode;
     641                 :     }
     642                 :     else
     643                 :     {
     644           11144 :         psLastChildParent->psNext = psCurNode;
     645                 :     }
     646           23174 :     sNodeLastChild.psLastChild = psCurNode;
     647                 : 
     648                 :     /* Add attributes to the element */
     649           23174 :     CPLXMLNode* psLastChildCurNode = AddAttributes(psCurNode, attr);
     650                 : 
     651                 :     /* Some CityGML lack a srsDimension="3" in posList, such as in */
     652                 :     /* http://www.citygml.org/fileadmin/count.php?f=fileadmin%2Fcitygml%2Fdocs%2FFrankfurt_Street_Setting_LOD3.zip */
     653                 :     /* So we have to add it manually */
     654           23174 :     if (m_bIsCityGML && nLenName == 7 &&
     655                 :         strcmp(pszName, "posList") == 0 &&
     656                 :         CPLGetXMLValue(psCurNode, "srsDimension", NULL) == NULL)
     657                 :     {
     658               0 :         CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, "srsDimension");
     659               0 :         CPLCreateXMLNode(psChild, CXT_Text, "3");
     660                 : 
     661               0 :         if (psLastChildCurNode == NULL)
     662               0 :             psCurNode->psChild = psChild;
     663                 :         else
     664               0 :             psLastChildCurNode->psNext = psChild;
     665               0 :         psLastChildCurNode = psChild;
     666                 :     }
     667                 : 
     668                 :     /* Push the element on the stack */
     669                 :     NodeLastChild sNewNodeLastChild;
     670           23174 :     sNewNodeLastChild.psNode = psCurNode;
     671           23174 :     sNewNodeLastChild.psLastChild = psLastChildCurNode;
     672           23174 :     apsXMLNode.push_back(sNewNodeLastChild);
     673                 : 
     674           23174 :     if (m_pszGeometry)
     675                 :     {
     676               0 :         CPLFree(m_pszGeometry);
     677               0 :         m_pszGeometry = NULL;
     678               0 :         m_nGeomAlloc = 0;
     679               0 :         m_nGeomLen = 0;
     680                 :     }
     681                 : 
     682           23174 :     return OGRERR_NONE;
     683                 : }
     684                 : 
     685                 : /************************************************************************/
     686                 : /*                    startElementCityGMLGenericAttr()                  */
     687                 : /************************************************************************/
     688                 : 
     689               6 : OGRErr GMLHandler::startElementCityGMLGenericAttr(const char *pszName, int nLenName, void* attr )
     690                 : {
     691               6 :     if( strcmp(pszName, "value") == 0 )
     692                 :     {
     693               6 :         if(m_pszCurField)
     694                 :         {
     695               0 :             CPLFree(m_pszCurField);
     696               0 :             m_pszCurField = NULL;
     697               0 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     698                 :         }
     699               6 :         m_bInCurField = TRUE;
     700                 :     }
     701                 : 
     702               6 :     return OGRERR_NONE;
     703                 : }
     704                 : /************************************************************************/
     705                 : /*                      startElementFeatureAttribute()                  */
     706                 : /************************************************************************/
     707                 : 
     708           21644 : OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
     709                 : {
     710                 :     /* Reset flag */
     711           21644 :     m_bInCurField = FALSE;
     712                 : 
     713           21644 :     GMLReadState *poState = m_poReader->GetState();
     714                 : 
     715                 : /* -------------------------------------------------------------------- */
     716                 : /*      If we are collecting geometry, or if we determine this is a     */
     717                 : /*      geometry element then append to the geometry info.              */
     718                 : /* -------------------------------------------------------------------- */
     719           21644 :     if( IsGeometryElement( pszName ) )
     720                 :     {
     721                 :         int bReadGeometry;
     722                 : 
     723                 :         /* If the <GeometryElementPath> is defined in the .gfs, use it */
     724                 :         /* to read the appropriate geometry element */
     725            2492 :         const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
     726            2492 :         if (pszGeometryElement != NULL)
     727            1454 :             bReadGeometry = strcmp(poState->osPath.c_str(), pszGeometryElement) == 0;
     728            1038 :         else if( m_poReader->FetchAllGeometries() )
     729                 :         {
     730               0 :             bReadGeometry = TRUE;
     731                 :         }
     732                 :         else
     733                 :         {
     734                 :             /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
     735                 :             /* not 'start' and 'end' geometries */
     736            1038 :             if (m_bIsAIXM &&
     737                 :                 strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
     738               0 :                 bReadGeometry = strcmp( pszName, "Curve") == 0;
     739                 : 
     740                 :             /* For Inspire objects : the "main" geometry is in a <geometry> element */
     741            1038 :             else if (m_bAlreadyFoundGeometry)
     742               2 :                 bReadGeometry = FALSE;
     743            1036 :             else if (strcmp( poState->osPath.c_str(), "geometry") == 0)
     744                 :             {
     745               8 :                 m_bAlreadyFoundGeometry = TRUE;
     746               8 :                 bReadGeometry = TRUE;
     747                 :             }
     748                 : 
     749                 :             else
     750            1028 :                 bReadGeometry = TRUE;
     751                 :         }
     752            2492 :         if (bReadGeometry)
     753                 :         {
     754            2488 :             m_nGeometryDepth = m_nDepth;
     755                 : 
     756            2488 :             CPLAssert(apsXMLNode.size() == 0);
     757                 : 
     758                 :             NodeLastChild sNodeLastChild;
     759            2488 :             sNodeLastChild.psNode = NULL;
     760            2488 :             sNodeLastChild.psLastChild = NULL;
     761            2488 :             apsXMLNode.push_back(sNodeLastChild);
     762                 : 
     763            2488 :             PUSH_STATE(STATE_GEOMETRY);
     764                 : 
     765            2488 :             return startElementGeometry(pszName, nLenName, attr);
     766                 :         }
     767                 :     }
     768                 : 
     769                 : 
     770           19152 :     else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     771                 :     {
     772             741 :         m_inBoundedByDepth = m_nDepth;
     773                 : 
     774             741 :         PUSH_STATE(STATE_BOUNDED_BY);
     775                 : 
     776             741 :         return OGRERR_NONE;
     777                 :     }
     778                 : 
     779                 : /* -------------------------------------------------------------------- */
     780                 : /*      Is it a CityGML generic attribute ?                             */
     781                 : /* -------------------------------------------------------------------- */
     782           18411 :     else if( m_bIsCityGML &&
     783                 :              m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
     784                 :     {
     785               6 :         CPLFree(m_pszCityGMLGenericAttrName);
     786               6 :         m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
     787               6 :         m_inCityGMLGenericAttrDepth = m_nDepth;
     788                 : 
     789               6 :         PUSH_STATE(STATE_CITYGML_ATTRIBUTE);
     790                 : 
     791               6 :         return OGRERR_NONE;
     792                 :     }
     793                 : 
     794                 : /* -------------------------------------------------------------------- */
     795                 : /*      If it is (or at least potentially is) a simple attribute,       */
     796                 : /*      then start collecting it.                                       */
     797                 : /* -------------------------------------------------------------------- */
     798           18405 :     else if( (m_nAttributeIndex =
     799                 :                 m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
     800                 :     {
     801           16594 :         if(m_pszCurField)
     802                 :         {
     803             568 :             CPLFree(m_pszCurField);
     804             568 :             m_pszCurField = NULL;
     805             568 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     806                 :         }
     807           16594 :         m_bInCurField = TRUE;
     808           16594 :         if (m_bReportHref)
     809                 :         {
     810               0 :             CPLFree(m_pszHref);
     811               0 :             m_pszHref = GetAttributeValue(attr, "xlink:href");
     812                 :         }
     813           16594 :         CPLFree(m_pszUom);
     814           16594 :         m_pszUom = GetAttributeValue(attr, "uom");
     815           16594 :         CPLFree(m_pszValue);
     816           16594 :         m_pszValue = GetAttributeValue(attr, "value");
     817                 : 
     818           16594 :         if (stateStack[nStackDepth] != STATE_PROPERTY)
     819                 :         {
     820           16564 :             m_nAttributeDepth = m_nDepth;
     821           16564 :             PUSH_STATE(STATE_PROPERTY);
     822                 :         }
     823                 : 
     824                 :     }
     825            1811 :     else if( m_bReportHref && (m_nAttributeIndex =
     826                 :                 m_poReader->GetAttributeElementIndex( CPLSPrintf("%s_href", pszName ),
     827                 :                                                       nLenName + 5 )) != -1 )
     828                 :     {
     829               0 :         if(m_pszCurField)
     830                 :         {
     831               0 :             CPLFree(m_pszCurField);
     832               0 :             m_pszCurField = NULL;
     833               0 :             m_nCurFieldLen = m_nCurFieldAlloc = 0;
     834                 :         }
     835               0 :         m_bInCurField = TRUE;
     836               0 :         CPLFree(m_pszHref);
     837               0 :         m_pszHref = GetAttributeValue(attr, "xlink:href");
     838                 : 
     839               0 :         if (stateStack[nStackDepth] != STATE_PROPERTY)
     840                 :         {
     841               0 :             m_nAttributeDepth = m_nDepth;
     842               0 :             PUSH_STATE(STATE_PROPERTY);
     843                 :         }
     844                 :     }
     845                 : 
     846           18409 :     poState->PushPath( pszName, nLenName );
     847                 : 
     848           18409 :     return OGRERR_NONE;
     849                 : }
     850                 : 
     851                 : /************************************************************************/
     852                 : /*                         startElementTop()                            */
     853                 : /************************************************************************/
     854                 : 
     855             200 : OGRErr GMLHandler::startElementTop(const char *pszName, int nLenName, void* attr )
     856                 : 
     857                 : {
     858             200 :     if (strcmp(pszName, "CityModel") == 0 )
     859                 :     {
     860               2 :         m_bIsCityGML = TRUE;
     861                 :     }
     862             198 :     else if (strcmp(pszName, "AIXMBasicMessage") == 0)
     863                 :     {
     864               0 :         m_bIsAIXM = m_bReportHref = TRUE;
     865                 :     }
     866                 : 
     867             200 :     stateStack[0] = STATE_DEFAULT;
     868                 : 
     869             200 :     return OGRERR_NONE;
     870                 : }
     871                 : 
     872                 : /************************************************************************/
     873                 : /*                        startElementDefault()                         */
     874                 : /************************************************************************/
     875                 : 
     876            6905 : OGRErr GMLHandler::startElementDefault(const char *pszName, int nLenName, void* attr )
     877                 : 
     878                 : {
     879                 : /* -------------------------------------------------------------------- */
     880                 : /*      Is it a feature?  If so push a whole new state, and return.     */
     881                 : /* -------------------------------------------------------------------- */
     882                 :     int nClassIndex;
     883            6905 :     if( (nClassIndex = m_poReader->GetFeatureElementIndex( pszName, nLenName )) != -1 )
     884                 :     {
     885            2508 :         m_bAlreadyFoundGeometry = FALSE;
     886                 : 
     887            2508 :         const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
     888            2508 :         if ( pszFilteredClassName != NULL &&
     889                 :              strcmp(pszName, pszFilteredClassName) != 0 )
     890                 :         {
     891               0 :             m_nDepthFeature = m_nDepth;
     892                 : 
     893               0 :             PUSH_STATE(STATE_IGNORED_FEATURE);
     894                 : 
     895               0 :             return OGRERR_NONE;
     896                 :         }
     897                 :         else
     898                 :         {
     899            2508 :             m_poReader->PushFeature( pszName, GetFID(attr), nClassIndex );
     900                 : 
     901            2508 :             m_nDepthFeature = m_nDepth;
     902                 : 
     903            2508 :             PUSH_STATE(STATE_FEATURE);
     904                 : 
     905            2508 :             return OGRERR_NONE;
     906                 :         }
     907                 :     }
     908                 : 
     909            4397 :     else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
     910                 :     {
     911             163 :         m_inBoundedByDepth = m_nDepth;
     912                 : 
     913             163 :         PUSH_STATE(STATE_BOUNDED_BY);
     914                 : 
     915             163 :         return OGRERR_NONE;
     916                 :     }
     917                 : 
     918                 : /* -------------------------------------------------------------------- */
     919                 : /*      Push the element onto the current state's path.                 */
     920                 : /* -------------------------------------------------------------------- */
     921            4234 :     m_poReader->GetState()->PushPath( pszName, nLenName );
     922                 : 
     923            4234 :     return OGRERR_NONE;
     924                 : }
     925                 : 
     926                 : /************************************************************************/
     927                 : /*                      endElementIgnoredFeature()                      */
     928                 : /************************************************************************/
     929                 : 
     930               0 : OGRErr GMLHandler::endElementIgnoredFeature()
     931                 : 
     932                 : {
     933               0 :     if (m_nDepth == m_nDepthFeature)
     934                 :     {
     935               0 :         POP_STATE();
     936                 :     }
     937               0 :     return OGRERR_NONE;
     938                 : }
     939                 : 
     940                 : /************************************************************************/
     941                 : /*                         endElementBoundedBy()                        */
     942                 : /************************************************************************/
     943            3690 : OGRErr GMLHandler::endElementBoundedBy()
     944                 : 
     945                 : {
     946            3690 :     if( m_inBoundedByDepth == m_nDepth)
     947                 :     {
     948             904 :         POP_STATE();
     949                 :     }
     950                 : 
     951            3690 :     return OGRERR_NONE;
     952                 : }
     953                 : 
     954                 : /************************************************************************/
     955                 : /*                       ParseAIXMElevationPoint()                      */
     956                 : /************************************************************************/
     957                 : 
     958               0 : CPLXMLNode* GMLHandler::ParseAIXMElevationPoint(CPLXMLNode *psGML)
     959                 : {
     960                 :     const char* pszElevation =
     961               0 :         CPLGetXMLValue( psGML, "elevation", NULL );
     962               0 :     if (pszElevation)
     963                 :     {
     964                 :         m_poReader->SetFeaturePropertyDirectly( "elevation",
     965               0 :                                         CPLStrdup(pszElevation), -1 );
     966                 :         const char* pszElevationUnit =
     967               0 :             CPLGetXMLValue( psGML, "elevation.uom", NULL );
     968               0 :         if (pszElevationUnit)
     969                 :         {
     970                 :             m_poReader->SetFeaturePropertyDirectly( "elevation_uom",
     971               0 :                                             CPLStrdup(pszElevationUnit), -1 );
     972                 :         }
     973                 :     }
     974                 : 
     975                 :     const char* pszGeoidUndulation =
     976               0 :         CPLGetXMLValue( psGML, "geoidUndulation", NULL );
     977               0 :     if (pszGeoidUndulation)
     978                 :     {
     979                 :         m_poReader->SetFeaturePropertyDirectly( "geoidUndulation",
     980               0 :                                         CPLStrdup(pszGeoidUndulation), -1 );
     981                 :         const char* pszGeoidUndulationUnit =
     982               0 :             CPLGetXMLValue( psGML, "geoidUndulation.uom", NULL );
     983               0 :         if (pszGeoidUndulationUnit)
     984                 :         {
     985                 :             m_poReader->SetFeaturePropertyDirectly( "geoidUndulation_uom",
     986               0 :                                             CPLStrdup(pszGeoidUndulationUnit), -1 );
     987                 :         }
     988                 :     }
     989                 : 
     990                 :     const char* pszPos =
     991               0 :                     CPLGetXMLValue( psGML, "pos", NULL );
     992                 :     const char* pszCoordinates =
     993               0 :                 CPLGetXMLValue( psGML, "coordinates", NULL );
     994               0 :     if (pszPos != NULL)
     995                 :     {
     996                 :         char* pszGeometry = CPLStrdup(CPLSPrintf(
     997                 :             "<gml:Point><gml:pos>%s</gml:pos></gml:Point>",
     998               0 :                                                     pszPos));
     999               0 :         CPLDestroyXMLNode(psGML);
    1000               0 :         psGML = CPLParseXMLString(pszGeometry);
    1001               0 :         CPLFree(pszGeometry);
    1002                 :     }
    1003               0 :     else if (pszCoordinates != NULL)
    1004                 :     {
    1005                 :         char* pszGeometry = CPLStrdup(CPLSPrintf(
    1006                 :             "<gml:Point><gml:coordinates>%s</gml:coordinates></gml:Point>",
    1007               0 :                                             pszCoordinates));
    1008               0 :         CPLDestroyXMLNode(psGML);
    1009               0 :         psGML = CPLParseXMLString(pszGeometry);
    1010               0 :         CPLFree(pszGeometry);
    1011                 :     }
    1012                 :     else
    1013                 :     {
    1014               0 :         CPLDestroyXMLNode(psGML);
    1015               0 :         psGML = NULL;
    1016                 :     }
    1017                 : 
    1018               0 :     return psGML;
    1019                 : }
    1020                 : 
    1021                 : /************************************************************************/
    1022                 : /*                         endElementGeometry()                         */
    1023                 : /************************************************************************/
    1024           23143 : OGRErr GMLHandler::endElementGeometry()
    1025                 : 
    1026                 : {
    1027           23143 :     if (m_nGeomLen)
    1028                 :     {
    1029            3825 :         CPLXMLNode* psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
    1030            3825 :         psNode->eType = CXT_Text;
    1031            3825 :         psNode->pszValue = m_pszGeometry;
    1032                 : 
    1033            3825 :         NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
    1034            3825 :         CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
    1035            3825 :         if (psLastChildParent == NULL)
    1036                 :         {
    1037            2314 :             CPLXMLNode* psParent = sNodeLastChild.psNode;
    1038            2314 :             if (psParent)
    1039            2314 :                 psParent->psChild = psNode;
    1040                 :         }
    1041                 :         else
    1042            1511 :             psLastChildParent->psNext = psNode;
    1043            3825 :         sNodeLastChild.psLastChild = psNode;
    1044                 : 
    1045            3825 :         m_pszGeometry = NULL;
    1046            3825 :         m_nGeomAlloc = 0;
    1047            3825 :         m_nGeomLen = 0;
    1048                 :     }
    1049                 : 
    1050           23143 :     if( m_nDepth == m_nGeometryDepth )
    1051                 :     {
    1052            2482 :         CPLXMLNode* psInterestNode = apsXMLNode[apsXMLNode.size()-1].psNode;
    1053                 : 
    1054                 :         /*char* pszXML = CPLSerializeXMLTree(psInterestNode);
    1055                 :         CPLDebug("GML", "geometry = %s", pszXML);
    1056                 :         CPLFree(pszXML);*/
    1057                 : 
    1058            2482 :         apsXMLNode.pop_back();
    1059                 : 
    1060                 :         /* AIXM ElevatedPoint. We want to parse this */
    1061                 :         /* a bit specially because ElevatedPoint is aixm: stuff and */
    1062                 :         /* the srsDimension of the <gml:pos> can be set to TRUE although */
    1063                 :         /* they are only 2 coordinates in practice */
    1064            2482 :         if ( m_bIsAIXM && psInterestNode != NULL &&
    1065                 :             strcmp(psInterestNode->pszValue, "ElevatedPoint") == 0 )
    1066                 :         {
    1067               0 :             psInterestNode = ParseAIXMElevationPoint(psInterestNode);
    1068                 :         }
    1069                 : 
    1070            2482 :         if (m_poReader->FetchAllGeometries())
    1071               0 :             m_poReader->GetState()->m_poFeature->AddGeometry(psInterestNode);
    1072                 :         else
    1073            2482 :             m_poReader->GetState()->m_poFeature->SetGeometryDirectly(psInterestNode);
    1074                 : 
    1075            2482 :         POP_STATE();
    1076                 :     }
    1077                 : 
    1078           23143 :     apsXMLNode.pop_back();
    1079                 : 
    1080           23143 :     return OGRERR_NONE;
    1081                 : }
    1082                 : 
    1083                 : /************************************************************************/
    1084                 : /*                    endElementCityGMLGenericAttr()                    */
    1085                 : /************************************************************************/
    1086              12 : OGRErr GMLHandler::endElementCityGMLGenericAttr()
    1087                 : 
    1088                 : {
    1089              12 :     if( m_pszCityGMLGenericAttrName != NULL && m_bInCurField )
    1090                 :     {
    1091                 :         m_poReader->SetFeaturePropertyDirectly( m_pszCityGMLGenericAttrName,
    1092               6 :                                         m_pszCurField, -1 );
    1093               6 :         m_pszCurField = NULL;
    1094               6 :         m_nCurFieldLen = m_nCurFieldAlloc = 0;
    1095               6 :         m_bInCurField = FALSE;
    1096               6 :         CPLFree(m_pszCityGMLGenericAttrName);
    1097               6 :         m_pszCityGMLGenericAttrName = NULL;
    1098                 :     }
    1099                 : 
    1100              12 :     if( m_inCityGMLGenericAttrDepth == m_nDepth )
    1101                 :     {
    1102               6 :         POP_STATE();
    1103                 :     }
    1104                 : 
    1105              12 :     return OGRERR_NONE;
    1106                 : }
    1107                 : 
    1108                 : /************************************************************************/
    1109                 : /*                        endElementAttribute()                         */
    1110                 : /************************************************************************/
    1111           16595 : OGRErr GMLHandler::endElementAttribute()
    1112                 : 
    1113                 : {
    1114           16595 :     GMLReadState *poState = m_poReader->GetState();
    1115                 : 
    1116           16595 :     if (m_bInCurField)
    1117                 :     {
    1118           15888 :         if (m_pszCurField == NULL)
    1119                 :         {
    1120             543 :             if (m_pszValue != NULL)
    1121                 :             {
    1122                 :                 m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
    1123              10 :                                                 m_pszValue, -1 );
    1124              10 :                 m_pszValue = NULL;
    1125                 :             }
    1126                 :         }
    1127                 :         else
    1128                 :         {
    1129                 :             m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
    1130                 :                                             m_pszCurField,
    1131           15345 :                                             m_nAttributeIndex );
    1132           15345 :             m_pszCurField = NULL;
    1133                 :         }
    1134                 : 
    1135           15888 :         if (m_pszHref != NULL)
    1136                 :         {
    1137               0 :             CPLString osPropNameHref = poState->osPath + "_href";
    1138               0 :             m_poReader->SetFeaturePropertyDirectly( osPropNameHref, m_pszHref, -1 );
    1139               0 :             m_pszHref = NULL;
    1140                 :         }
    1141                 : 
    1142           15888 :         if (m_pszUom != NULL)
    1143                 :         {
    1144              10 :             CPLString osPropNameUom = poState->osPath + "_uom";
    1145              10 :             m_poReader->SetFeaturePropertyDirectly( osPropNameUom, m_pszUom, -1 );
    1146              10 :             m_pszUom = NULL;
    1147                 :         }
    1148                 : 
    1149           15888 :         m_nCurFieldLen = m_nCurFieldAlloc = 0;
    1150           15888 :         m_bInCurField = FALSE;
    1151           15888 :         m_nAttributeIndex = -1;
    1152                 : 
    1153           15888 :         CPLFree( m_pszValue );
    1154           15888 :         m_pszValue = NULL;
    1155                 :     }
    1156                 : 
    1157           16595 :     poState->PopPath();
    1158                 : 
    1159           16595 :     if( m_nAttributeDepth == m_nDepth )
    1160                 :     {
    1161           16563 :         POP_STATE();
    1162                 :     }
    1163                 : 
    1164           16595 :     return OGRERR_NONE;
    1165                 : }
    1166                 : 
    1167                 : /************************************************************************/
    1168                 : /*                          endElementFeature()                         */
    1169                 : /************************************************************************/
    1170            4311 : OGRErr GMLHandler::endElementFeature()
    1171                 : 
    1172                 : {
    1173                 : /* -------------------------------------------------------------------- */
    1174                 : /*      If we are collecting a feature, and this element tag matches    */
    1175                 : /*      element name for the class, then we have finished the           */
    1176                 : /*      feature, and we pop the feature read state.                     */
    1177                 : /* -------------------------------------------------------------------- */
    1178            4311 :     if( m_nDepth == m_nDepthFeature )
    1179                 :     {
    1180            2502 :         m_poReader->PopState();
    1181                 : 
    1182            2502 :         POP_STATE();
    1183                 :     }
    1184                 : 
    1185                 : /* -------------------------------------------------------------------- */
    1186                 : /*      Otherwise, we just pop the element off the local read states    */
    1187                 : /*      element stack.                                                  */
    1188                 : /* -------------------------------------------------------------------- */
    1189                 :     else
    1190                 :     {
    1191            1809 :         m_poReader->GetState()->PopPath();
    1192                 :     }
    1193                 : 
    1194            4311 :     return OGRERR_NONE;
    1195                 : }
    1196                 : 
    1197                 : /************************************************************************/
    1198                 : /*                          endElementDefault()                         */
    1199                 : /************************************************************************/
    1200            4422 : OGRErr GMLHandler::endElementDefault()
    1201                 : 
    1202                 : {
    1203            4422 :     if (m_nDepth > 0)
    1204            4228 :         m_poReader->GetState()->PopPath();
    1205                 : 
    1206            4422 :     return OGRERR_NONE;
    1207                 : }
    1208                 : 
    1209                 : /************************************************************************/
    1210                 : /*                         dataHandlerAttribute()                       */
    1211                 : /************************************************************************/
    1212                 : 
    1213           18160 : OGRErr GMLHandler::dataHandlerAttribute(const char *data, int nLen)
    1214                 : 
    1215                 : {
    1216           18160 :     int nIter = 0;
    1217                 : 
    1218           18160 :     if( m_bInCurField )
    1219                 :     {
    1220                 :         // Ignore white space
    1221           16793 :         if (m_nCurFieldLen == 0)
    1222                 :         {
    1223           39078 :             while (nIter < nLen)
    1224                 :             {
    1225           20847 :                 char ch = data[nIter];
    1226           20847 :                 if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
    1227           15351 :                     break;
    1228            5496 :                 nIter ++;
    1229                 :             }
    1230                 :         }
    1231                 : 
    1232           16793 :         int nCharsLen = nLen - nIter;
    1233                 : 
    1234           16793 :         if (m_nCurFieldLen + nCharsLen + 1 > m_nCurFieldAlloc)
    1235                 :         {
    1236           15940 :             m_nCurFieldAlloc = m_nCurFieldAlloc * 4 / 3 + nCharsLen + 1;
    1237                 :             char *pszNewCurField = (char *)
    1238           15940 :                 VSIRealloc( m_pszCurField, m_nCurFieldAlloc );
    1239           15940 :             if (pszNewCurField == NULL)
    1240                 :             {
    1241               0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    1242                 :             }
    1243           15940 :             m_pszCurField = pszNewCurField;
    1244                 :         }
    1245           16793 :         memcpy( m_pszCurField + m_nCurFieldLen, data + nIter, nCharsLen);
    1246           16793 :         m_nCurFieldLen += nCharsLen;
    1247           16793 :         m_pszCurField[m_nCurFieldLen] = '\0';
    1248                 :     }
    1249                 : 
    1250           18160 :     return OGRERR_NONE;
    1251                 : }
    1252                 : 
    1253                 : /************************************************************************/
    1254                 : /*                         dataHandlerGeometry()                        */
    1255                 : /************************************************************************/
    1256                 : 
    1257           71696 : OGRErr GMLHandler::dataHandlerGeometry(const char *data, int nLen)
    1258                 : 
    1259                 : {
    1260           71696 :     int nIter = 0;
    1261                 : 
    1262                 :     // Ignore white space
    1263           71696 :     if (m_nGeomLen == 0)
    1264                 :     {
    1265          617504 :         while (nIter < nLen)
    1266                 :         {
    1267          478258 :             char ch = data[nIter];
    1268          478258 :             if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
    1269            3826 :                 break;
    1270          474432 :             nIter ++;
    1271                 :         }
    1272                 :     }
    1273                 : 
    1274           71696 :     int nCharsLen = nLen - nIter;
    1275           71696 :     if (nCharsLen)
    1276                 :     {
    1277            3986 :         if( m_nGeomLen + nCharsLen + 1 > m_nGeomAlloc )
    1278                 :         {
    1279            3950 :             m_nGeomAlloc = m_nGeomAlloc * 4 / 3 + nCharsLen + 1;
    1280                 :             char* pszNewGeometry = (char *)
    1281            3950 :                 VSIRealloc( m_pszGeometry, m_nGeomAlloc);
    1282            3950 :             if (pszNewGeometry == NULL)
    1283                 :             {
    1284               0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    1285                 :             }
    1286            3950 :             m_pszGeometry = pszNewGeometry;
    1287                 :         }
    1288            3986 :         memcpy( m_pszGeometry+m_nGeomLen, data + nIter, nCharsLen);
    1289            3986 :         m_nGeomLen += nCharsLen;
    1290            3986 :         m_pszGeometry[m_nGeomLen] = '\0';
    1291                 :     }
    1292                 : 
    1293           71696 :     return OGRERR_NONE;
    1294                 : }
    1295                 : 
    1296                 : 
    1297                 : /************************************************************************/
    1298                 : /*                         IsGeometryElement()                          */
    1299                 : /************************************************************************/
    1300                 : 
    1301           21644 : int GMLHandler::IsGeometryElement( const char *pszElement )
    1302                 : 
    1303                 : {
    1304           21644 :     int nFirst = 0;
    1305           21644 :     int nLast = GML_GEOMETRY_TYPE_COUNT- 1;
    1306           21644 :     unsigned long nHash = CPLHashSetHashStr(pszElement);
    1307           96551 :     do
    1308                 :     {
    1309           99043 :         int nMiddle = (nFirst + nLast) / 2;
    1310           99043 :         if (nHash == pasGeometryNames[nMiddle].nHash)
    1311            2492 :             return strcmp(pszElement, pasGeometryNames[nMiddle].pszName) == 0;
    1312           96551 :         if (nHash < pasGeometryNames[nMiddle].nHash)
    1313           51772 :             nLast = nMiddle - 1;
    1314                 :         else
    1315           44779 :             nFirst = nMiddle + 1;
    1316                 :     } while(nFirst <= nLast);
    1317                 : 
    1318           19152 :     if (m_bIsAIXM && strcmp( pszElement, "ElevatedPoint") == 0)
    1319               0 :         return TRUE;
    1320                 : 
    1321           19152 :     return FALSE;
    1322                 : }

Generated by: LCOV version 1.7