LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - gmlreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 535 393 73.5 %
Date: 2012-04-28 Functions: 48 27 56.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: gmlreader.cpp 23647 2011-12-23 22:27:20Z rouault $
       3                 :  *
       4                 :  * Project:  GML Reader
       5                 :  * Purpose:  Implementation of GMLReader 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 "gmlreader.h"
      31                 : #include "cpl_error.h"
      32                 : #include "cpl_string.h"
      33                 : #include "gmlutils.h"
      34                 : #include "gmlreaderp.h"
      35                 : #include "cpl_conv.h"
      36                 : #include <map>
      37                 : 
      38                 : #define SUPPORT_GEOMETRY
      39                 : 
      40                 : #ifdef SUPPORT_GEOMETRY
      41                 : #  include "ogr_geometry.h"
      42                 : #endif
      43                 : 
      44                 : /************************************************************************/
      45                 : /*                            ~IGMLReader()                             */
      46                 : /************************************************************************/
      47                 : 
      48             154 : IGMLReader::~IGMLReader()
      49                 : 
      50                 : {
      51             154 : }
      52                 : 
      53                 : /************************************************************************/
      54                 : /* ==================================================================== */
      55                 : /*                  No XERCES or EXPAT Library                          */
      56                 : /* ==================================================================== */
      57                 : /************************************************************************/
      58                 : #if !defined(HAVE_XERCES) && !defined(HAVE_EXPAT)
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                          CreateGMLReader()                           */
      62                 : /************************************************************************/
      63                 : 
      64                 : IGMLReader *CreateGMLReader(int bUseExpatParserPreferably,
      65                 :                             int bInvertAxisOrderIfLatLong,
      66                 :                             int bConsiderEPSGAsURN,
      67                 :                             int bGetSecondaryGeometryOption)
      68                 : 
      69                 : {
      70                 :     CPLError( CE_Failure, CPLE_AppDefined,
      71                 :               "Unable to create Xerces C++ or Expat based GML reader, Xerces or Expat support\n"
      72                 :               "not configured into GDAL/OGR." );
      73                 :     return NULL;
      74                 : }
      75                 : 
      76                 : /************************************************************************/
      77                 : /* ==================================================================== */
      78                 : /*                  With XERCES or EXPAT Library                        */
      79                 : /* ==================================================================== */
      80                 : /************************************************************************/
      81                 : #else /* defined(HAVE_XERCES) || defined(HAVE_EXPAT) */
      82                 : 
      83                 : /************************************************************************/
      84                 : /*                          CreateGMLReader()                           */
      85                 : /************************************************************************/
      86                 : 
      87             144 : IGMLReader *CreateGMLReader(int bUseExpatParserPreferably,
      88                 :                             int bInvertAxisOrderIfLatLong,
      89                 :                             int bConsiderEPSGAsURN,
      90                 :                             int bGetSecondaryGeometryOption)
      91                 : 
      92                 : {
      93                 :     return new GMLReader(bUseExpatParserPreferably,
      94                 :                          bInvertAxisOrderIfLatLong,
      95                 :                          bConsiderEPSGAsURN,
      96             144 :                          bGetSecondaryGeometryOption);
      97                 : }
      98                 : 
      99                 : #endif
     100                 : 
     101                 : int GMLReader::m_bXercesInitialized = FALSE;
     102                 : int GMLReader::m_nInstanceCount = 0;
     103                 : 
     104                 : /************************************************************************/
     105                 : /*                             GMLReader()                              */
     106                 : /************************************************************************/
     107                 : 
     108             144 : GMLReader::GMLReader(int bUseExpatParserPreferably,
     109                 :                      int bInvertAxisOrderIfLatLong,
     110                 :                      int bConsiderEPSGAsURN,
     111             144 :                      int bGetSecondaryGeometryOption)
     112                 : 
     113                 : {
     114                 : #ifndef HAVE_XERCES
     115                 :     bUseExpatReader = TRUE;
     116                 : #else
     117             144 :     bUseExpatReader = FALSE;
     118                 : #ifdef HAVE_EXPAT
     119             144 :     if(bUseExpatParserPreferably)
     120             144 :         bUseExpatReader = TRUE;
     121                 : #endif
     122                 : #endif
     123                 : 
     124                 : #if defined(HAVE_EXPAT) && defined(HAVE_XERCES)
     125             144 :     if (bUseExpatReader)
     126             144 :         CPLDebug("GML", "Using Expat reader");
     127                 :     else
     128               0 :         CPLDebug("GML", "Using Xerces reader");
     129                 : #endif
     130                 : 
     131             144 :     m_nInstanceCount++;
     132             144 :     m_nClassCount = 0;
     133             144 :     m_papoClass = NULL;
     134                 : 
     135             144 :     m_bClassListLocked = FALSE;
     136                 : 
     137             144 :     m_poGMLHandler = NULL;
     138                 : #ifdef HAVE_XERCES
     139             144 :     m_poSAXReader = NULL;
     140             144 :     m_poCompleteFeature = NULL;
     141             144 :     m_GMLInputSource = NULL;
     142             144 :     m_bEOF = FALSE;
     143                 : #endif
     144                 : #ifdef HAVE_EXPAT
     145             144 :     oParser = NULL;
     146             144 :     ppoFeatureTab = NULL;
     147             144 :     nFeatureTabIndex = 0;
     148             144 :     nFeatureTabLength = 0;
     149             144 :     nFeatureTabAlloc = 0;
     150             144 :     pabyBuf = NULL;
     151                 : #endif
     152             144 :     fpGML = NULL;
     153             144 :     m_bReadStarted = FALSE;
     154                 :     
     155             144 :     m_poState = NULL;
     156             144 :     m_poRecycledState = NULL;
     157                 : 
     158             144 :     m_pszFilename = NULL;
     159                 : 
     160             144 :     m_bStopParsing = FALSE;
     161                 : 
     162                 :     /* A bit experimental. Not publicly advertized. See commented doc in drv_gml.html */
     163             144 :     m_bFetchAllGeometries = CSLTestBoolean(CPLGetConfigOption("GML_FETCH_ALL_GEOMETRIES", "NO"));
     164                 : 
     165             144 :     m_bInvertAxisOrderIfLatLong = bInvertAxisOrderIfLatLong;
     166             144 :     m_bConsiderEPSGAsURN = bConsiderEPSGAsURN;
     167             144 :     m_bGetSecondaryGeometryOption = bGetSecondaryGeometryOption;
     168                 : 
     169             144 :     m_pszGlobalSRSName = NULL;
     170             144 :     m_bCanUseGlobalSRSName = FALSE;
     171                 : 
     172             144 :     m_pszFilteredClassName = NULL;
     173                 : 
     174             144 :     m_bSequentialLayers = -1;
     175                 :   
     176                 :     /* Must be in synced in OGR_G_CreateFromGML(), OGRGMLLayer::OGRGMLLayer() and GMLReader::GMLReader() */
     177             144 :     m_bFaceHoleNegative = CSLTestBoolean(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO"));
     178             144 : }
     179                 : 
     180                 : /************************************************************************/
     181                 : /*                             ~GMLReader()                             */
     182                 : /************************************************************************/
     183                 : 
     184             144 : GMLReader::~GMLReader()
     185                 : 
     186                 : {
     187             144 :     ClearClasses();
     188                 : 
     189             144 :     CPLFree( m_pszFilename );
     190                 : 
     191             144 :     CleanupParser();
     192                 : 
     193             144 :     delete m_poRecycledState;
     194                 : 
     195             144 :     --m_nInstanceCount;
     196                 : #ifdef HAVE_XERCES
     197             144 :     if( m_nInstanceCount == 0 && m_bXercesInitialized )
     198                 :     {
     199               0 :         XMLPlatformUtils::Terminate();
     200               0 :         m_bXercesInitialized = FALSE;
     201                 :     }
     202                 : #endif
     203                 : #ifdef HAVE_EXPAT
     204             144 :     CPLFree(pabyBuf);
     205                 : #endif
     206                 : 
     207             144 :     if (fpGML)
     208             118 :         VSIFCloseL(fpGML);
     209             144 :     fpGML = NULL;
     210                 : 
     211             144 :     CPLFree(m_pszGlobalSRSName);
     212                 : 
     213             144 :     CPLFree(m_pszFilteredClassName);
     214             144 : }
     215                 : 
     216                 : /************************************************************************/
     217                 : /*                          SetSourceFile()                             */
     218                 : /************************************************************************/
     219                 : 
     220             150 : void GMLReader::SetSourceFile( const char *pszFilename )
     221                 : 
     222                 : {
     223             150 :     CPLFree( m_pszFilename );
     224             150 :     m_pszFilename = CPLStrdup( pszFilename );
     225             150 : }
     226                 : 
     227                 : /************************************************************************/
     228                 : /*                       GetSourceFileName()                           */
     229                 : /************************************************************************/
     230                 : 
     231               0 : const char* GMLReader::GetSourceFileName()
     232                 : 
     233                 : {
     234               0 :     return m_pszFilename;
     235                 : }
     236                 : 
     237                 : /************************************************************************/
     238                 : /*                            SetupParser()                             */
     239                 : /************************************************************************/
     240                 : 
     241             246 : int GMLReader::SetupParser()
     242                 : 
     243                 : {
     244             246 :     if (fpGML == NULL)
     245             122 :         fpGML = VSIFOpenL(m_pszFilename, "rt");
     246             246 :     if (fpGML != NULL)
     247             246 :         VSIFSeekL( fpGML, 0, SEEK_SET );
     248                 : 
     249             246 :     int bRet = -1;
     250                 : #ifdef HAVE_EXPAT
     251             246 :     if (bUseExpatReader)
     252             246 :         bRet = SetupParserExpat();
     253                 : #endif
     254                 : 
     255                 : #ifdef HAVE_XERCES
     256             246 :     if (!bUseExpatReader)
     257               0 :         bRet = SetupParserXerces();
     258                 : #endif
     259             246 :     if (bRet < 0)
     260                 :     {
     261               0 :         CPLError(CE_Failure, CPLE_AppDefined, "SetupParser(): shouldn't happen");
     262               0 :         return FALSE;
     263                 :     }
     264                 : 
     265             246 :     if (!bRet)
     266               0 :         return FALSE;
     267                 : 
     268             246 :     m_bReadStarted = FALSE;
     269                 : 
     270                 :     // Push an empty state.
     271             246 :     PushState( m_poRecycledState ? m_poRecycledState : new GMLReadState() );
     272             246 :     m_poRecycledState = NULL;
     273                 : 
     274             246 :     return TRUE;
     275                 : }
     276                 : 
     277                 : #ifdef HAVE_XERCES
     278                 : /************************************************************************/
     279                 : /*                        SetupParserXerces()                           */
     280                 : /************************************************************************/
     281                 : 
     282               0 : int GMLReader::SetupParserXerces()
     283                 : {
     284               0 :     if( !m_bXercesInitialized )
     285                 :     {
     286                 :         try
     287                 :         {
     288               0 :             XMLPlatformUtils::Initialize();
     289                 :         }
     290                 :         
     291               0 :         catch (const XMLException& toCatch)
     292                 :         {
     293                 :             CPLError( CE_Warning, CPLE_AppDefined,
     294                 :                       "Exception initializing Xerces based GML reader.\n%s", 
     295               0 :                       tr_strdup(toCatch.getMessage()) );
     296               0 :             return FALSE;
     297                 :         }
     298               0 :         m_bXercesInitialized = TRUE;
     299                 :     }
     300                 : 
     301                 :     // Cleanup any old parser.
     302               0 :     if( m_poSAXReader != NULL )
     303               0 :         CleanupParser();
     304                 : 
     305                 :     // Create and initialize parser.
     306               0 :     XMLCh* xmlUriValid = NULL;
     307               0 :     XMLCh* xmlUriNS = NULL;
     308                 : 
     309                 :     try{
     310               0 :         m_poSAXReader = XMLReaderFactory::createXMLReader();
     311                 :     
     312               0 :         GMLXercesHandler* poXercesHandler = new GMLXercesHandler( this );
     313               0 :         m_poGMLHandler = poXercesHandler;
     314                 : 
     315               0 :         m_poSAXReader->setContentHandler( poXercesHandler );
     316               0 :         m_poSAXReader->setErrorHandler( poXercesHandler );
     317               0 :         m_poSAXReader->setLexicalHandler( poXercesHandler );
     318               0 :         m_poSAXReader->setEntityResolver( poXercesHandler );
     319               0 :         m_poSAXReader->setDTDHandler( poXercesHandler );
     320                 : 
     321               0 :         xmlUriValid = XMLString::transcode("http://xml.org/sax/features/validation");
     322               0 :         xmlUriNS = XMLString::transcode("http://xml.org/sax/features/namespaces");
     323                 : 
     324                 : #if (OGR_GML_VALIDATION)
     325                 :         m_poSAXReader->setFeature( xmlUriValid, true);
     326                 :         m_poSAXReader->setFeature( xmlUriNS, true);
     327                 : 
     328                 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
     329                 :         m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
     330                 : 
     331                 : //    m_poSAXReader->setDoSchema(true);
     332                 : //    m_poSAXReader->setValidationSchemaFullChecking(true);
     333                 : #else
     334               0 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreValidation, false);
     335                 : 
     336                 : #if XERCES_VERSION_MAJOR >= 3
     337                 :         m_poSAXReader->setFeature( XMLUni::fgXercesSchema, false);
     338                 : #else
     339               0 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, false);
     340                 : #endif
     341                 : 
     342                 : #endif
     343               0 :         XMLString::release( &xmlUriValid );
     344               0 :         XMLString::release( &xmlUriNS );
     345                 :     }
     346               0 :     catch (...)
     347                 :     {
     348               0 :         XMLString::release( &xmlUriValid );
     349               0 :         XMLString::release( &xmlUriNS );
     350                 : 
     351                 :         CPLError( CE_Warning, CPLE_AppDefined,
     352               0 :                   "Exception initializing Xerces based GML reader.\n" );
     353               0 :         return FALSE;
     354                 :     }
     355                 : 
     356               0 :     if (m_GMLInputSource == NULL && fpGML != NULL)
     357               0 :         m_GMLInputSource = new GMLInputSource(fpGML);
     358                 : 
     359               0 :     return TRUE;
     360                 : }
     361                 : #endif
     362                 : 
     363                 : /************************************************************************/
     364                 : /*                        SetupParserExpat()                            */
     365                 : /************************************************************************/
     366                 : 
     367                 : #ifdef HAVE_EXPAT
     368             246 : int GMLReader::SetupParserExpat()
     369                 : {
     370                 :     // Cleanup any old parser.
     371             246 :     if( oParser != NULL )
     372               4 :         CleanupParser();
     373                 : 
     374             246 :     oParser = OGRCreateExpatXMLParser();
     375             246 :     m_poGMLHandler = new GMLExpatHandler( this, oParser );
     376                 : 
     377             246 :     XML_SetElementHandler(oParser, GMLExpatHandler::startElementCbk, GMLExpatHandler::endElementCbk);
     378             246 :     XML_SetCharacterDataHandler(oParser, GMLExpatHandler::dataHandlerCbk);
     379             246 :     XML_SetUserData(oParser, m_poGMLHandler);
     380                 : 
     381             246 :     if (pabyBuf == NULL)
     382             118 :         pabyBuf = (char*)VSIMalloc(PARSER_BUF_SIZE);
     383             246 :     if (pabyBuf == NULL)
     384               0 :         return FALSE;
     385                 : 
     386             246 :     return TRUE;
     387                 : }
     388                 : #endif
     389                 : 
     390                 : /************************************************************************/
     391                 : /*                           CleanupParser()                            */
     392                 : /************************************************************************/
     393                 : 
     394             518 : void GMLReader::CleanupParser()
     395                 : 
     396                 : {
     397                 : #ifdef HAVE_XERCES
     398             518 :     if( !bUseExpatReader && m_poSAXReader == NULL )
     399               0 :         return;
     400                 : #endif
     401                 : 
     402                 : #ifdef HAVE_EXPAT
     403             518 :     if ( bUseExpatReader && oParser == NULL )
     404             272 :         return;
     405                 : #endif
     406                 : 
     407             744 :     while( m_poState )
     408             252 :         PopState();
     409                 : 
     410                 : #ifdef HAVE_XERCES
     411             246 :     delete m_poSAXReader;
     412             246 :     m_poSAXReader = NULL;
     413             246 :     delete m_GMLInputSource;
     414             246 :     m_GMLInputSource = NULL;
     415             246 :     delete m_poCompleteFeature;
     416             246 :     m_poCompleteFeature = NULL;
     417             246 :     m_bEOF = FALSE;
     418                 : #endif
     419                 : 
     420                 : #ifdef HAVE_EXPAT
     421             246 :     if (oParser)
     422             246 :         XML_ParserFree(oParser);
     423             246 :     oParser = NULL;
     424                 : 
     425                 :     int i;
     426             662 :     for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
     427             416 :         delete ppoFeatureTab[i];
     428             246 :     CPLFree(ppoFeatureTab);
     429             246 :     nFeatureTabIndex = 0;
     430             246 :     nFeatureTabLength = 0;
     431             246 :     nFeatureTabAlloc = 0;
     432             246 :     ppoFeatureTab = NULL;
     433                 : 
     434                 : #endif
     435                 : 
     436             246 :     delete m_poGMLHandler;
     437             246 :     m_poGMLHandler = NULL;
     438                 : 
     439             246 :     m_bReadStarted = FALSE;
     440                 : }
     441                 : 
     442                 : #ifdef HAVE_XERCES
     443                 : 
     444               0 : GMLBinInputStream::GMLBinInputStream(VSILFILE* fp)
     445                 : {
     446               0 :     this->fp = fp;
     447               0 :     emptyString = 0;
     448               0 : }
     449                 : 
     450               0 : GMLBinInputStream::~ GMLBinInputStream()
     451                 : {
     452               0 : }
     453                 : 
     454                 : #if XERCES_VERSION_MAJOR >= 3
     455                 : XMLFilePos GMLBinInputStream::curPos() const
     456                 : {
     457                 :     return (XMLFilePos)VSIFTellL(fp);
     458                 : }
     459                 : 
     460                 : XMLSize_t GMLBinInputStream::readBytes(XMLByte* const toFill, const XMLSize_t maxToRead)
     461                 : {
     462                 :     return (XMLSize_t)VSIFReadL(toFill, 1, maxToRead, fp);
     463                 : }
     464                 : 
     465                 : const XMLCh* GMLBinInputStream::getContentType() const
     466                 : {
     467                 :     return &emptyString;
     468                 : }
     469                 : #else
     470               0 : unsigned int GMLBinInputStream::curPos() const
     471                 : {
     472               0 :     return (unsigned int)VSIFTellL(fp);
     473                 : }
     474                 : 
     475               0 : unsigned int GMLBinInputStream::readBytes(XMLByte* const toFill, const unsigned int maxToRead)
     476                 : {
     477               0 :     return (unsigned int)VSIFReadL(toFill, 1, maxToRead, fp);
     478                 : }
     479                 : #endif
     480                 : 
     481               0 : GMLInputSource::GMLInputSource(VSILFILE* fp, MemoryManager* const manager) : InputSource(manager)
     482                 : {
     483               0 :     binInputStream = new GMLBinInputStream(fp);
     484               0 : }
     485                 : 
     486               0 : GMLInputSource::~GMLInputSource()
     487                 : {
     488               0 : }
     489                 : 
     490               0 : BinInputStream* GMLInputSource::makeStream() const
     491                 : {
     492               0 :     return binInputStream;
     493                 : }
     494                 : 
     495                 : #endif // HAVE_XERCES
     496                 : 
     497                 : /************************************************************************/
     498                 : /*                        NextFeatureXerces()                           */
     499                 : /************************************************************************/
     500                 : 
     501                 : #ifdef HAVE_XERCES
     502               0 : GMLFeature *GMLReader::NextFeatureXerces()
     503                 : 
     504                 : {
     505               0 :     GMLFeature *poReturn = NULL;
     506                 : 
     507               0 :     if (m_bEOF)
     508               0 :         return NULL;
     509                 : 
     510                 :     try
     511                 :     {
     512               0 :         if( !m_bReadStarted )
     513                 :         {
     514               0 :             if( m_poSAXReader == NULL )
     515               0 :                 SetupParser();
     516                 : 
     517               0 :             m_bReadStarted = TRUE;
     518                 : 
     519               0 :             if (m_GMLInputSource == NULL)
     520               0 :                 return NULL;
     521                 : 
     522               0 :             if( !m_poSAXReader->parseFirst( *m_GMLInputSource, m_oToFill ) )
     523               0 :                 return NULL;
     524                 :         }
     525                 : 
     526               0 :         while( m_poCompleteFeature == NULL 
     527                 :                && !m_bStopParsing
     528               0 :                && m_poSAXReader->parseNext( m_oToFill ) ) {}
     529                 : 
     530               0 :         if (m_poCompleteFeature == NULL)
     531               0 :             m_bEOF = TRUE;
     532                 : 
     533               0 :         poReturn = m_poCompleteFeature;
     534               0 :         m_poCompleteFeature = NULL;
     535                 : 
     536                 :     }
     537               0 :     catch (const XMLException& toCatch)
     538                 :     {
     539               0 :         char *pszErrorMessage = tr_strdup( toCatch.getMessage() );
     540                 :         CPLDebug( "GML", 
     541                 :                   "Error during NextFeature()! Message:\n%s", 
     542               0 :                   pszErrorMessage );
     543               0 :         CPLFree(pszErrorMessage);
     544               0 :         m_bStopParsing = TRUE;
     545                 :     }
     546               0 :     catch (const SAXException& toCatch)
     547                 :     {
     548               0 :         char *pszErrorMessage = tr_strdup( toCatch.getMessage() );
     549               0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
     550               0 :         CPLFree(pszErrorMessage);
     551               0 :         m_bStopParsing = TRUE;
     552                 :     }
     553                 : 
     554               0 :     return poReturn;
     555                 : }
     556                 : #endif
     557                 : 
     558                 : #ifdef HAVE_EXPAT
     559            2560 : GMLFeature *GMLReader::NextFeatureExpat()
     560                 : 
     561                 : {
     562            2560 :     if (!m_bReadStarted)
     563                 :     {
     564             246 :         if (oParser == NULL)
     565             188 :             SetupParser();
     566                 : 
     567             246 :         m_bReadStarted = TRUE;
     568                 :     }
     569                 : 
     570            2560 :     if (fpGML == NULL || m_bStopParsing)
     571               0 :         return NULL;
     572                 : 
     573            2560 :     if (nFeatureTabIndex < nFeatureTabLength)
     574                 :     {
     575            2160 :         return ppoFeatureTab[nFeatureTabIndex++];
     576                 :     }
     577                 : 
     578             400 :     if (VSIFEofL(fpGML))
     579             148 :         return NULL;
     580                 : 
     581             252 :     nFeatureTabLength = 0;
     582             252 :     nFeatureTabIndex = 0;
     583                 : 
     584                 :     int nDone;
     585             252 :     do
     586                 :     {
     587                 :         /* Reset counter that is used to detect billion laugh attacks */
     588             252 :         ((GMLExpatHandler*)m_poGMLHandler)->ResetDataHandlerCounter();
     589                 : 
     590                 :         unsigned int nLen =
     591             252 :                 (unsigned int)VSIFReadL( pabyBuf, 1, PARSER_BUF_SIZE, fpGML );
     592             252 :         nDone = VSIFEofL(fpGML);
     593             252 :         if (XML_Parse(oParser, pabyBuf, nLen, nDone) == XML_STATUS_ERROR)
     594                 :         {
     595                 :             CPLError(CE_Failure, CPLE_AppDefined,
     596                 :                      "XML parsing of GML file failed : %s "
     597                 :                      "at line %d, column %d",
     598                 :                      XML_ErrorString(XML_GetErrorCode(oParser)),
     599                 :                      (int)XML_GetCurrentLineNumber(oParser),
     600               0 :                      (int)XML_GetCurrentColumnNumber(oParser));
     601               0 :             m_bStopParsing = TRUE;
     602                 :         }
     603             252 :         if (!m_bStopParsing)
     604             252 :             m_bStopParsing = ((GMLExpatHandler*)m_poGMLHandler)->HasStoppedParsing();
     605                 : 
     606                 :     } while (!nDone && !m_bStopParsing && nFeatureTabLength == 0);
     607                 : 
     608             252 :     return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
     609                 : }
     610                 : #endif
     611                 : 
     612            2560 : GMLFeature *GMLReader::NextFeature()
     613                 : {
     614                 : #ifdef HAVE_EXPAT
     615            2560 :     if (bUseExpatReader)
     616            2560 :         return NextFeatureExpat();
     617                 : #endif
     618                 : 
     619                 : #ifdef HAVE_XERCES
     620               0 :     if (!bUseExpatReader)
     621               0 :         return NextFeatureXerces();
     622                 : #endif
     623                 : 
     624               0 :     CPLError(CE_Failure, CPLE_AppDefined, "NextFeature(): Should not happen");
     625               0 :     return NULL;
     626                 : }
     627                 : 
     628                 : /************************************************************************/
     629                 : /*                            PushFeature()                             */
     630                 : /*                                                                      */
     631                 : /*      Create a feature based on the named element.  If the            */
     632                 : /*      corresponding feature class doesn't exist yet, then create      */
     633                 : /*      it now.  A new GMLReadState will be created for the feature,    */
     634                 : /*      and it will be placed within that state.  The state is          */
     635                 : /*      pushed onto the readstate stack.                                */
     636                 : /************************************************************************/
     637                 : 
     638            2826 : void GMLReader::PushFeature( const char *pszElement, 
     639                 :                              const char *pszFID,
     640                 :                              int nClassIndex )
     641                 : 
     642                 : {
     643                 :     int iClass;
     644                 : 
     645            2826 :     if( nClassIndex != INT_MAX )
     646                 :     {
     647            1074 :         iClass = nClassIndex;
     648                 :     }
     649                 :     else
     650                 :     {
     651                 :     /* -------------------------------------------------------------------- */
     652                 :     /*      Find the class of this element.                                 */
     653                 :     /* -------------------------------------------------------------------- */
     654            2302 :         for( iClass = 0; iClass < m_nClassCount; iClass++ )
     655                 :         {
     656            2222 :             if( EQUAL(pszElement,m_papoClass[iClass]->GetElementName()) )
     657            1672 :                 break;
     658                 :         }
     659                 : 
     660                 :     /* -------------------------------------------------------------------- */
     661                 :     /*      Create a new feature class for this element, if there is no     */
     662                 :     /*      existing class for it.                                          */
     663                 :     /* -------------------------------------------------------------------- */
     664            1752 :         if( iClass == m_nClassCount )
     665                 :         {
     666              80 :             CPLAssert( !m_bClassListLocked );
     667                 : 
     668              80 :             GMLFeatureClass *poNewClass = new GMLFeatureClass( pszElement );
     669                 : 
     670              80 :             AddClass( poNewClass );
     671                 :         }
     672                 :     }
     673                 : 
     674                 : /* -------------------------------------------------------------------- */
     675                 : /*      Create a feature of this feature class.  Try to set the fid     */
     676                 : /*      if available.                                                   */
     677                 : /* -------------------------------------------------------------------- */
     678            2826 :     GMLFeature *poFeature = new GMLFeature( m_papoClass[iClass] );
     679            2826 :     if( pszFID != NULL )
     680                 :     {
     681             980 :         poFeature->SetFID( pszFID );
     682                 :     }
     683                 : 
     684                 : /* -------------------------------------------------------------------- */
     685                 : /*      Create and push a new read state.                               */
     686                 : /* -------------------------------------------------------------------- */
     687                 :     GMLReadState *poState;
     688                 : 
     689            2826 :     poState = m_poRecycledState ? m_poRecycledState : new GMLReadState();
     690            2826 :     m_poRecycledState = NULL;
     691            2826 :     poState->m_poFeature = poFeature;
     692            2826 :     PushState( poState );
     693            2826 : }
     694                 : 
     695                 : /************************************************************************/
     696                 : /*                          IsFeatureElement()                          */
     697                 : /*                                                                      */
     698                 : /*      Based on context and the element name, is this element a new    */
     699                 : /*      GML feature element?                                            */
     700                 : /************************************************************************/
     701                 : 
     702            4712 : int GMLReader::GetFeatureElementIndex( const char *pszElement, int nElementLength )
     703                 : 
     704                 : {
     705            4712 :     const char *pszLast = m_poState->GetLastComponent();
     706            4712 :     size_t      nLenLast = m_poState->GetLastComponentLen();
     707                 : 
     708            4712 :     if( (nLenLast >= 6 && EQUAL(pszLast+nLenLast-6,"member")) ||
     709                 :         (nLenLast >= 7 && EQUAL(pszLast+nLenLast-7,"members")) )
     710                 :     {
     711                 :         /* Default feature name */
     712                 :     }
     713                 :     else
     714                 :     {
     715            1884 :         if (nLenLast == 4 && strcmp(pszLast, "dane") == 0)
     716                 :         {
     717                 :             /* Polish TBD GML */
     718                 :         }
     719                 : 
     720                 :         /* Begin of OpenLS */
     721            1884 :         else if (nLenLast == 19 && nElementLength == 15 &&
     722                 :                  strcmp(pszLast, "GeocodeResponseList") == 0 &&
     723                 :                  strcmp(pszElement, "GeocodedAddress") == 0)
     724                 :         {
     725                 :         }
     726            1888 :         else if (nLenLast == 22 &&
     727                 :                  strcmp(pszLast, "DetermineRouteResponse") == 0)
     728                 :         {
     729                 :             /* We don't want the children of RouteInstructionsList */
     730                 :             /* to be a single feature. We want each RouteInstruction */
     731                 :             /* to be a feature */
     732               6 :             if (strcmp(pszElement, "RouteInstructionsList") == 0)
     733               2 :                 return -1;
     734                 :         }
     735            1878 :         else if (nElementLength == 16 && nLenLast == 21 &&
     736                 :                  strcmp(pszElement, "RouteInstruction") == 0 &&
     737                 :                  strcmp(pszLast, "RouteInstructionsList") == 0)
     738                 :         {
     739                 :         }
     740                 :         /* End of OpenLS */
     741                 : 
     742            1860 :         else if (nLenLast > 6 && strcmp(pszLast + nLenLast - 6, "_layer") == 0 &&
     743                 :                  nElementLength > 8 && strcmp(pszElement + nElementLength - 8, "_feature") == 0)
     744                 :         {
     745                 :             /* GML answer of MapServer WMS GetFeatureInfo request */
     746                 :         }
     747                 :         else
     748            1860 :             return -1;
     749                 :     }
     750                 : 
     751                 :     // If the class list isn't locked, any element that is a featureMember
     752                 :     // will do. 
     753            2850 :     if( !m_bClassListLocked )
     754            1752 :         return INT_MAX;
     755                 : 
     756                 :     // otherwise, find a class with the desired element name.
     757            1320 :     for( int i = 0; i < m_nClassCount; i++ )
     758                 :     {
     759            2526 :         if( nElementLength == (int)m_papoClass[i]->GetElementNameLen() &&
     760            1206 :             memcmp(pszElement,m_papoClass[i]->GetElementName(), nElementLength) == 0 )
     761            1098 :             return i;
     762                 :     }
     763                 : 
     764               0 :     return -1;
     765                 : }
     766                 : 
     767                 : /************************************************************************/
     768                 : /*                IsCityGMLGenericAttributeElement()                    */
     769                 : /************************************************************************/
     770                 : 
     771              24 : int GMLReader::IsCityGMLGenericAttributeElement( const char *pszElement, void* attr )
     772                 : 
     773                 : {
     774              24 :     if( strcmp(pszElement, "stringAttribute") != 0 &&
     775                 :         strcmp(pszElement, "intAttribute") != 0 &&
     776                 :         strcmp(pszElement, "doubleAttribute") != 0 )
     777              12 :         return FALSE;
     778                 : 
     779              12 :     char* pszVal = m_poGMLHandler->GetAttributeValue(attr, "name");
     780              12 :     if (pszVal == NULL)
     781               0 :         return FALSE;
     782                 : 
     783              12 :     GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
     784                 : 
     785                 :     // If the schema is not yet locked, then any simple element
     786                 :     // is potentially an attribute.
     787              12 :     if( !poClass->IsSchemaLocked() )
     788                 :     {
     789              12 :         CPLFree(pszVal);
     790              12 :         return TRUE;
     791                 :     }
     792                 : 
     793               0 :     for( int i = 0; i < poClass->GetPropertyCount(); i++ )
     794                 :     {
     795               0 :         if( strcmp(poClass->GetProperty(i)->GetSrcElement(),pszVal) == 0 )
     796                 :         {
     797               0 :             CPLFree(pszVal);
     798               0 :             return TRUE;
     799                 :         }
     800                 :     }
     801                 : 
     802               0 :     CPLFree(pszVal);
     803               0 :     return FALSE;
     804                 : }
     805                 : 
     806                 : /************************************************************************/
     807                 : /*                       GetAttributeElementIndex()                     */
     808                 : /************************************************************************/
     809                 : 
     810           10430 : int GMLReader::GetAttributeElementIndex( const char *pszElement, int nLen )
     811                 : 
     812                 : {
     813           10430 :     GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
     814                 : 
     815                 :     // If the schema is not yet locked, then any simple element
     816                 :     // is potentially an attribute.
     817           10430 :     if( !poClass->IsSchemaLocked() )
     818            6728 :         return INT_MAX;
     819                 : 
     820                 :     // Otherwise build the path to this element into a single string
     821                 :     // and compare against known attributes.
     822            3702 :     if( m_poState->m_nPathLength == 0 )
     823            3678 :         return poClass->GetPropertyIndexBySrcElement(pszElement, nLen);
     824                 :     else
     825                 :     {
     826              24 :         int nFullLen = nLen + m_poState->osPath.size() + 1;
     827              24 :         osElemPath.reserve(nFullLen);
     828              24 :         osElemPath.assign(m_poState->osPath);
     829              24 :         osElemPath.append(1, '|');
     830              24 :         osElemPath.append(pszElement, nLen);
     831              24 :         return poClass->GetPropertyIndexBySrcElement(osElemPath.c_str(), nFullLen);
     832                 :     }
     833                 : }
     834                 : 
     835                 : /************************************************************************/
     836                 : /*                              PopState()                              */
     837                 : /************************************************************************/
     838                 : 
     839            3072 : void GMLReader::PopState()
     840                 : 
     841                 : {
     842            3072 :     if( m_poState != NULL )
     843                 :     {
     844                 : #ifdef HAVE_XERCES
     845            3072 :         if( !bUseExpatReader && m_poState->m_poFeature != NULL &&
     846                 :             m_poCompleteFeature == NULL )
     847                 :         {
     848               0 :             m_poCompleteFeature = m_poState->m_poFeature;
     849               0 :             m_poState->m_poFeature = NULL;
     850                 :         }
     851                 : #endif
     852                 : 
     853                 : #ifdef HAVE_EXPAT
     854            3072 :         if ( bUseExpatReader && m_poState->m_poFeature != NULL )
     855                 :         {
     856            2826 :             if (nFeatureTabLength >= nFeatureTabAlloc)
     857                 :             {
     858             308 :                 nFeatureTabAlloc = nFeatureTabLength * 4 / 3 + 16;
     859                 :                 ppoFeatureTab = (GMLFeature**)
     860                 :                         CPLRealloc(ppoFeatureTab,
     861             308 :                                     sizeof(GMLFeature*) * (nFeatureTabAlloc));
     862                 :             }
     863            2826 :             ppoFeatureTab[nFeatureTabLength] = m_poState->m_poFeature;
     864            2826 :             nFeatureTabLength++;
     865                 : 
     866            2826 :             m_poState->m_poFeature = NULL;
     867                 :         }
     868                 : #endif
     869                 : 
     870                 :         GMLReadState *poParent;
     871                 : 
     872            3072 :         poParent = m_poState->m_poParentState;
     873                 :         
     874            3072 :         delete m_poRecycledState;
     875            3072 :         m_poRecycledState = m_poState;
     876            3072 :         m_poRecycledState->Reset();
     877            3072 :         m_poState = poParent;
     878                 :     }
     879            3072 : }
     880                 : 
     881                 : /************************************************************************/
     882                 : /*                             PushState()                              */
     883                 : /************************************************************************/
     884                 : 
     885            3072 : void GMLReader::PushState( GMLReadState *poState )
     886                 : 
     887                 : {
     888            3072 :     poState->m_poParentState = m_poState;
     889            3072 :     m_poState = poState;
     890            3072 : }
     891                 : 
     892                 : /************************************************************************/
     893                 : /*                              GetClass()                              */
     894                 : /************************************************************************/
     895                 : 
     896             816 : GMLFeatureClass *GMLReader::GetClass( int iClass ) const
     897                 : 
     898                 : {
     899             816 :     if( iClass < 0 || iClass >= m_nClassCount )
     900               0 :         return NULL;
     901                 :     else
     902             816 :         return m_papoClass[iClass];
     903                 : }
     904                 : 
     905                 : /************************************************************************/
     906                 : /*                              GetClass()                              */
     907                 : /************************************************************************/
     908                 : 
     909             424 : GMLFeatureClass *GMLReader::GetClass( const char *pszName ) const
     910                 : 
     911                 : {
     912             600 :     for( int iClass = 0; iClass < m_nClassCount; iClass++ )
     913                 :     {
     914             382 :         if( EQUAL(GetClass(iClass)->GetName(),pszName) )
     915             206 :             return GetClass(iClass);
     916                 :     }
     917                 : 
     918             218 :     return NULL;
     919                 : }
     920                 : 
     921                 : /************************************************************************/
     922                 : /*                              AddClass()                              */
     923                 : /************************************************************************/
     924                 : 
     925             214 : int GMLReader::AddClass( GMLFeatureClass *poNewClass )
     926                 : 
     927                 : {
     928             214 :     CPLAssert( GetClass( poNewClass->GetName() ) == NULL );
     929                 : 
     930             214 :     m_nClassCount++;
     931                 :     m_papoClass = (GMLFeatureClass **) 
     932             214 :         CPLRealloc( m_papoClass, sizeof(void*) * m_nClassCount );
     933             214 :     m_papoClass[m_nClassCount-1] = poNewClass;
     934                 : 
     935             214 :     return m_nClassCount-1;
     936                 : }
     937                 : 
     938                 : /************************************************************************/
     939                 : /*                            ClearClasses()                            */
     940                 : /************************************************************************/
     941                 : 
     942             194 : void GMLReader::ClearClasses()
     943                 : 
     944                 : {
     945             400 :     for( int i = 0; i < m_nClassCount; i++ )
     946             206 :         delete m_papoClass[i];
     947             194 :     CPLFree( m_papoClass );
     948                 : 
     949             194 :     m_nClassCount = 0;
     950             194 :     m_papoClass = NULL;
     951             194 : }
     952                 : 
     953                 : /************************************************************************/
     954                 : /*                     SetFeaturePropertyDirectly()                     */
     955                 : /*                                                                      */
     956                 : /*      Set the property value on the current feature, adding the       */
     957                 : /*      property name to the GMLFeatureClass if required.               */
     958                 : /*      The pszValue ownership is passed to this function.              */
     959                 : /************************************************************************/
     960                 : 
     961            7858 : void GMLReader::SetFeaturePropertyDirectly( const char *pszElement, 
     962                 :                                             char *pszValue,
     963                 :                                             int iPropertyIn )
     964                 : 
     965                 : {
     966            7858 :     GMLFeature *poFeature = GetState()->m_poFeature;
     967                 : 
     968            7858 :     CPLAssert( poFeature  != NULL );
     969                 : 
     970                 : /* -------------------------------------------------------------------- */
     971                 : /*      Does this property exist in the feature class?  If not, add     */
     972                 : /*      it.                                                             */
     973                 : /* -------------------------------------------------------------------- */
     974            7858 :     GMLFeatureClass *poClass = poFeature->GetClass();
     975                 :     int      iProperty;
     976                 : 
     977            7858 :     int nPropertyCount = poClass->GetPropertyCount();
     978           10476 :     if (iPropertyIn >= 0 && iPropertyIn < nPropertyCount)
     979                 :     {
     980            2618 :         iProperty = iPropertyIn;
     981                 :     }
     982                 :     else
     983                 :     {
     984           15978 :         for( iProperty=0; iProperty < nPropertyCount; iProperty++ )
     985                 :         {
     986           15754 :             if( strcmp(poClass->GetProperty( iProperty )->GetSrcElement(),
     987                 :                     pszElement ) == 0 )
     988            5016 :                 break;
     989                 :         }
     990                 : 
     991            5240 :         if( iProperty == nPropertyCount )
     992                 :         {
     993             224 :             if( poClass->IsSchemaLocked() )
     994                 :             {
     995               0 :                 CPLDebug("GML","Encountered property missing from class schema.");
     996               0 :                 CPLFree(pszValue);
     997               0 :                 return;
     998                 :             }
     999                 : 
    1000             224 :             CPLString osFieldName;
    1001                 : 
    1002             224 :             if( strchr(pszElement,'|') == NULL )
    1003             214 :                 osFieldName = pszElement;
    1004                 :             else
    1005                 :             {
    1006              10 :                 osFieldName = strrchr(pszElement,'|') + 1;
    1007              10 :                 if( poClass->GetPropertyIndex(osFieldName) != -1 )
    1008               0 :                     osFieldName = pszElement;
    1009                 :             }
    1010                 : 
    1011                 :             // Does this conflict with an existing property name?
    1012             450 :             while( poClass->GetProperty(osFieldName) != NULL )
    1013                 :             {
    1014               2 :                 osFieldName += "_";
    1015                 :             }
    1016                 : 
    1017             224 :             GMLPropertyDefn *poPDefn = new GMLPropertyDefn(osFieldName,pszElement);
    1018                 : 
    1019             448 :             if( EQUAL(CPLGetConfigOption( "GML_FIELDTYPES", ""), "ALWAYS_STRING") )
    1020               0 :                 poPDefn->SetType( GMLPT_String );
    1021                 : 
    1022             224 :             if (poClass->AddProperty( poPDefn ) < 0)
    1023                 :             {
    1024               0 :                 delete poPDefn;
    1025               0 :                 CPLFree(pszValue);
    1026                 :                 return;
    1027               0 :             }
    1028                 :         }
    1029                 :     }
    1030                 : 
    1031                 : /* -------------------------------------------------------------------- */
    1032                 : /*      Set the property                                                */
    1033                 : /* -------------------------------------------------------------------- */
    1034            7858 :     poFeature->SetPropertyDirectly( iProperty, pszValue );
    1035                 : 
    1036                 : /* -------------------------------------------------------------------- */
    1037                 : /*      Do we need to update the property type?                         */
    1038                 : /* -------------------------------------------------------------------- */
    1039            7858 :     if( !poClass->IsSchemaLocked() )
    1040                 :     {
    1041                 :         poClass->GetProperty(iProperty)->AnalysePropertyValue(
    1042            5240 :                              poFeature->GetProperty(iProperty));
    1043                 :     }
    1044                 : }
    1045                 : 
    1046                 : /************************************************************************/
    1047                 : /*                            LoadClasses()                             */
    1048                 : /************************************************************************/
    1049                 : 
    1050              32 : int GMLReader::LoadClasses( const char *pszFile )
    1051                 : 
    1052                 : {
    1053                 :     // Add logic later to determine reasonable default schema file. 
    1054              32 :     if( pszFile == NULL )
    1055               0 :         return FALSE;
    1056                 : 
    1057                 : /* -------------------------------------------------------------------- */
    1058                 : /*      Load the raw XML file.                                          */
    1059                 : /* -------------------------------------------------------------------- */
    1060                 :     VSILFILE       *fp;
    1061                 :     int         nLength;
    1062                 :     char        *pszWholeText;
    1063                 : 
    1064              32 :     fp = VSIFOpenL( pszFile, "rb" );
    1065                 : 
    1066              32 :     if( fp == NULL )
    1067                 :     {
    1068                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    1069               0 :                   "Failed to open file %s.", pszFile );
    1070               0 :         return FALSE;
    1071                 :     }
    1072                 : 
    1073              32 :     VSIFSeekL( fp, 0, SEEK_END );
    1074              32 :     nLength = (int) VSIFTellL( fp );
    1075              32 :     VSIFSeekL( fp, 0, SEEK_SET );
    1076                 : 
    1077              32 :     pszWholeText = (char *) VSIMalloc(nLength+1);
    1078              32 :     if( pszWholeText == NULL )
    1079                 :     {
    1080                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1081                 :                   "Failed to allocate %d byte buffer for %s,\n"
    1082                 :                   "is this really a GMLFeatureClassList file?",
    1083               0 :                   nLength, pszFile );
    1084               0 :         VSIFCloseL( fp );
    1085               0 :         return FALSE;
    1086                 :     }
    1087                 :     
    1088              32 :     if( VSIFReadL( pszWholeText, nLength, 1, fp ) != 1 )
    1089                 :     {
    1090               0 :         VSIFree( pszWholeText );
    1091               0 :         VSIFCloseL( fp );
    1092                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1093               0 :                   "Read failed on %s.", pszFile );
    1094               0 :         return FALSE;
    1095                 :     }
    1096              32 :     pszWholeText[nLength] = '\0';
    1097                 : 
    1098              32 :     VSIFCloseL( fp );
    1099                 : 
    1100              32 :     if( strstr( pszWholeText, "<GMLFeatureClassList>" ) == NULL )
    1101                 :     {
    1102               0 :         VSIFree( pszWholeText );
    1103                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1104                 :                   "File %s does not contain a GMLFeatureClassList tree.",
    1105               0 :                   pszFile );
    1106               0 :         return FALSE;
    1107                 :     }
    1108                 : 
    1109                 : /* -------------------------------------------------------------------- */
    1110                 : /*      Convert to XML parse tree.                                      */
    1111                 : /* -------------------------------------------------------------------- */
    1112                 :     CPLXMLNode *psRoot;
    1113                 : 
    1114              32 :     psRoot = CPLParseXMLString( pszWholeText );
    1115              32 :     VSIFree( pszWholeText );
    1116                 : 
    1117                 :     // We assume parser will report errors via CPL.
    1118              32 :     if( psRoot == NULL )
    1119               0 :         return FALSE;
    1120                 : 
    1121              32 :     if( psRoot->eType != CXT_Element 
    1122                 :         || !EQUAL(psRoot->pszValue,"GMLFeatureClassList") )
    1123                 :     {
    1124               0 :         CPLDestroyXMLNode(psRoot);
    1125                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1126                 :                   "File %s is not a GMLFeatureClassList document.",
    1127               0 :                   pszFile );
    1128               0 :         return FALSE;
    1129                 :     }
    1130                 : 
    1131              32 :     const char* pszSequentialLayers = CPLGetXMLValue(psRoot, "SequentialLayers", NULL);
    1132              32 :     if (pszSequentialLayers)
    1133               8 :         m_bSequentialLayers = CSLTestBoolean(pszSequentialLayers);
    1134                 : 
    1135                 : /* -------------------------------------------------------------------- */
    1136                 : /*      Extract feature classes for all definitions found.              */
    1137                 : /* -------------------------------------------------------------------- */
    1138                 :     CPLXMLNode *psThis;
    1139                 : 
    1140              92 :     for( psThis = psRoot->psChild; psThis != NULL; psThis = psThis->psNext )
    1141                 :     {
    1142              60 :         if( psThis->eType == CXT_Element 
    1143                 :             && EQUAL(psThis->pszValue,"GMLFeatureClass") )
    1144                 :         {
    1145                 :             GMLFeatureClass   *poClass;
    1146                 : 
    1147              52 :             poClass = new GMLFeatureClass();
    1148                 : 
    1149              52 :             if( !poClass->InitializeFromXML( psThis ) )
    1150                 :             {
    1151               0 :                 delete poClass;
    1152               0 :                 CPLDestroyXMLNode( psRoot );
    1153               0 :                 return FALSE;
    1154                 :             }
    1155                 : 
    1156              52 :             poClass->SetSchemaLocked( TRUE );
    1157                 : 
    1158              52 :             AddClass( poClass );
    1159                 :         }
    1160                 :     }
    1161                 : 
    1162              32 :     CPLDestroyXMLNode( psRoot );
    1163                 :     
    1164              32 :     SetClassListLocked( TRUE );
    1165                 : 
    1166              32 :     return TRUE;
    1167                 : }
    1168                 : 
    1169                 : /************************************************************************/
    1170                 : /*                            SaveClasses()                             */
    1171                 : /************************************************************************/
    1172                 : 
    1173              48 : int GMLReader::SaveClasses( const char *pszFile )
    1174                 : 
    1175                 : {
    1176                 :     // Add logic later to determine reasonable default schema file. 
    1177              48 :     if( pszFile == NULL )
    1178               0 :         return FALSE;
    1179                 : 
    1180                 : /* -------------------------------------------------------------------- */
    1181                 : /*      Create in memory schema tree.                                   */
    1182                 : /* -------------------------------------------------------------------- */
    1183                 :     CPLXMLNode *psRoot;
    1184                 : 
    1185              48 :     psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClassList" );
    1186                 : 
    1187              48 :     if (m_bSequentialLayers != -1 && m_nClassCount > 1)
    1188                 :     {
    1189                 :         CPLCreateXMLElementAndValue( psRoot, "SequentialLayers",
    1190              16 :                                      m_bSequentialLayers ? "true" : "false" );
    1191                 :     }
    1192                 : 
    1193             120 :     for( int iClass = 0; iClass < m_nClassCount; iClass++ )
    1194                 :     {
    1195              72 :         CPLAddXMLChild( psRoot, m_papoClass[iClass]->SerializeToXML() );
    1196                 :     }
    1197                 : 
    1198                 : /* -------------------------------------------------------------------- */
    1199                 : /*      Serialize to disk.                                              */
    1200                 : /* -------------------------------------------------------------------- */
    1201                 :     VSILFILE        *fp;
    1202              48 :     int         bSuccess = TRUE;
    1203              48 :     char        *pszWholeText = CPLSerializeXMLTree( psRoot );
    1204                 :     
    1205              48 :     CPLDestroyXMLNode( psRoot );
    1206                 :  
    1207              48 :     fp = VSIFOpenL( pszFile, "wb" );
    1208                 :     
    1209              48 :     if( fp == NULL )
    1210               0 :         bSuccess = FALSE;
    1211              48 :     else if( VSIFWriteL( pszWholeText, strlen(pszWholeText), 1, fp ) != 1 )
    1212               0 :         bSuccess = FALSE;
    1213                 :     else
    1214              48 :         VSIFCloseL( fp );
    1215                 : 
    1216              48 :     CPLFree( pszWholeText );
    1217                 : 
    1218              48 :     return bSuccess;
    1219                 : }
    1220                 : 
    1221                 : /************************************************************************/
    1222                 : /*                          PrescanForSchema()                          */
    1223                 : /*                                                                      */
    1224                 : /*      For now we use a pretty dumb approach of just doing a normal    */
    1225                 : /*      scan of the whole file, building up the schema information.     */
    1226                 : /*      Eventually we hope to do a more efficient scan when just        */
    1227                 : /*      looking for schema information.                                 */
    1228                 : /************************************************************************/
    1229                 : 
    1230              50 : int GMLReader::PrescanForSchema( int bGetExtents )
    1231                 : 
    1232                 : {
    1233                 :     GMLFeature  *poFeature;
    1234                 : 
    1235              50 :     if( m_pszFilename == NULL )
    1236               0 :         return FALSE;
    1237                 : 
    1238              50 :     SetClassListLocked( FALSE );
    1239                 : 
    1240              50 :     ClearClasses();
    1241              50 :     if( !SetupParser() )
    1242               0 :         return FALSE;
    1243                 : 
    1244              50 :     m_bCanUseGlobalSRSName = TRUE;
    1245                 : 
    1246              50 :     std::map<GMLFeatureClass*, int> osMapCountFeatureWithoutGeometry;
    1247              50 :     GMLFeatureClass *poLastClass = NULL;
    1248                 : 
    1249              50 :     m_bSequentialLayers = TRUE;
    1250                 : 
    1251              50 :     void* hCacheSRS = GML_BuildOGRGeometryFromList_CreateCache();
    1252                 : 
    1253              50 :     std::string osWork;
    1254                 : 
    1255             840 :     while( (poFeature = NextFeature()) != NULL )
    1256                 :     {
    1257             740 :         GMLFeatureClass *poClass = poFeature->GetClass();
    1258                 : 
    1259             740 :         if (poLastClass != NULL && poClass != poLastClass &&
    1260                 :             poClass->GetFeatureCount() != -1)
    1261               0 :             m_bSequentialLayers = FALSE;
    1262             740 :         poLastClass = poClass;
    1263                 : 
    1264             740 :         if( poClass->GetFeatureCount() == -1 )
    1265              72 :             poClass->SetFeatureCount( 1 );
    1266                 :         else
    1267             668 :             poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
    1268                 : 
    1269             740 :         const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList();
    1270             740 :         if (papsGeometry[0] == NULL)
    1271                 :         {
    1272                 :             std::map<GMLFeatureClass*, int>::iterator oIter =
    1273              16 :                 osMapCountFeatureWithoutGeometry.find(poClass);
    1274              16 :             if (oIter == osMapCountFeatureWithoutGeometry.end())
    1275               4 :                 osMapCountFeatureWithoutGeometry[poClass] = 1;
    1276                 :             else
    1277              12 :                 oIter->second ++;
    1278                 :         }
    1279                 : 
    1280                 : 
    1281                 : #ifdef SUPPORT_GEOMETRY
    1282             740 :         if( bGetExtents )
    1283                 :         {
    1284                 :             OGRGeometry *poGeometry = GML_BuildOGRGeometryFromList(
    1285                 :                 papsGeometry, TRUE, m_bInvertAxisOrderIfLatLong,
    1286                 :                 NULL, m_bConsiderEPSGAsURN, m_bGetSecondaryGeometryOption, 
    1287             740 :                 hCacheSRS, m_bFaceHoleNegative );
    1288                 : 
    1289             740 :             if( poGeometry != NULL )
    1290                 :             {
    1291                 :                 double  dfXMin, dfXMax, dfYMin, dfYMax;
    1292             724 :                 OGREnvelope sEnvelope;
    1293                 :                 OGRwkbGeometryType eGType = (OGRwkbGeometryType) 
    1294             724 :                     poClass->GetGeometryType();
    1295                 : 
    1296                 :                 const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry,
    1297                 :                                                                         osWork,
    1298             724 :                                                                         m_bConsiderEPSGAsURN);
    1299             724 :                 if (pszSRSName != NULL)
    1300             182 :                     m_bCanUseGlobalSRSName = FALSE;
    1301             724 :                 poClass->MergeSRSName(pszSRSName);
    1302                 : 
    1303                 :                 // Merge geometry type into layer.
    1304             724 :                 if( poClass->GetFeatureCount() == 1 && eGType == wkbUnknown )
    1305              68 :                     eGType = wkbNone;
    1306                 : 
    1307                 :                 poClass->SetGeometryType( 
    1308                 :                     (int) OGRMergeGeometryTypes(
    1309             724 :                         eGType, poGeometry->getGeometryType() ) );
    1310                 : 
    1311                 :                 // merge extents.
    1312             724 :                 if (!poGeometry->IsEmpty())
    1313                 :                 {
    1314             724 :                     poGeometry->getEnvelope( &sEnvelope );
    1315             724 :                     if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
    1316                 :                     {
    1317             656 :                         dfXMin = MIN(dfXMin,sEnvelope.MinX);
    1318             656 :                         dfXMax = MAX(dfXMax,sEnvelope.MaxX);
    1319             656 :                         dfYMin = MIN(dfYMin,sEnvelope.MinY);
    1320             656 :                         dfYMax = MAX(dfYMax,sEnvelope.MaxY);
    1321                 :                     }
    1322                 :                     else
    1323                 :                     {
    1324              68 :                         dfXMin = sEnvelope.MinX;
    1325              68 :                         dfXMax = sEnvelope.MaxX;
    1326              68 :                         dfYMin = sEnvelope.MinY;
    1327              68 :                         dfYMax = sEnvelope.MaxY;
    1328                 :                     }
    1329                 : 
    1330             724 :                     poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax );
    1331                 :                 }
    1332             724 :                 delete poGeometry;
    1333                 : 
    1334                 :             }
    1335                 : #endif /* def SUPPORT_GEOMETRY */
    1336                 :         }
    1337                 :         
    1338             740 :         delete poFeature;
    1339                 :     }
    1340                 : 
    1341              50 :     GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
    1342                 : 
    1343             122 :     for( int i = 0; i < m_nClassCount; i++ )
    1344                 :     {
    1345              72 :         GMLFeatureClass *poClass = m_papoClass[i];
    1346              72 :         const char* pszSRSName = poClass->GetSRSName();
    1347                 : 
    1348              72 :         if (m_bCanUseGlobalSRSName)
    1349              46 :             pszSRSName = m_pszGlobalSRSName;
    1350                 :         
    1351              72 :         if (m_bInvertAxisOrderIfLatLong && GML_IsSRSLatLongOrder(pszSRSName))
    1352                 :         {
    1353              12 :             OGRSpatialReference oSRS;
    1354              12 :             if (oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE)
    1355                 :             {
    1356              12 :                 OGR_SRSNode *poGEOGCS = oSRS.GetAttrNode( "GEOGCS" );
    1357              12 :                 if( poGEOGCS != NULL )
    1358                 :                 {
    1359              12 :                     poGEOGCS->StripNodes( "AXIS" );
    1360                 : 
    1361              12 :                     char* pszWKT = NULL;
    1362              12 :                     if (oSRS.exportToWkt(&pszWKT) == OGRERR_NONE)
    1363              12 :                         poClass->SetSRSName(pszWKT);
    1364              12 :                     CPLFree(pszWKT);
    1365                 : 
    1366                 :                     /* So when we have computed the extent, we didn't know yet */
    1367                 :                     /* the SRS to use. Now we know it, we have to fix the extent */
    1368                 :                     /* order */
    1369              12 :                     if (m_bCanUseGlobalSRSName)
    1370                 :                     {
    1371                 :                         double  dfXMin, dfXMax, dfYMin, dfYMax;
    1372               2 :                         if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
    1373               2 :                             poClass->SetExtents( dfYMin, dfYMax, dfXMin, dfXMax );
    1374                 :                     }
    1375                 :                 }
    1376              12 :             }
    1377                 :         }
    1378                 : 
    1379                 :         std::map<GMLFeatureClass*, int>::iterator oIter =
    1380              72 :                 osMapCountFeatureWithoutGeometry.find(poClass);
    1381              72 :         if (oIter != osMapCountFeatureWithoutGeometry.end() &&
    1382                 :             oIter->second == poClass->GetFeatureCount())
    1383                 :         {
    1384               4 :             poClass->SetGeometryType(wkbNone);
    1385                 :         }
    1386                 :     }
    1387                 : 
    1388              50 :     CleanupParser();
    1389                 : 
    1390              50 :     return m_nClassCount > 0;
    1391                 : }
    1392                 : 
    1393                 : /************************************************************************/
    1394                 : /*                            ResetReading()                            */
    1395                 : /************************************************************************/
    1396                 : 
    1397             316 : void GMLReader::ResetReading()
    1398                 : 
    1399                 : {
    1400             316 :     CleanupParser();
    1401             316 :     SetFilteredClassName(NULL);
    1402             316 : }
    1403                 : 
    1404                 : /************************************************************************/
    1405                 : /*                          SetGlobalSRSName()                          */
    1406                 : /************************************************************************/
    1407                 : 
    1408             116 : void GMLReader::SetGlobalSRSName( const char* pszGlobalSRSName )
    1409                 : {
    1410             116 :     if (m_pszGlobalSRSName == NULL && pszGlobalSRSName != NULL)
    1411                 :     {
    1412              64 :         if (strncmp(pszGlobalSRSName, "EPSG:", 5) == 0 &&
    1413                 :             m_bConsiderEPSGAsURN)
    1414                 :         {
    1415                 :             m_pszGlobalSRSName = CPLStrdup(CPLSPrintf("urn:ogc:def:crs:EPSG::%s",
    1416              10 :                                                       pszGlobalSRSName+5));
    1417                 :         }
    1418                 :         else
    1419                 :         {
    1420              44 :             m_pszGlobalSRSName = CPLStrdup(pszGlobalSRSName);
    1421                 :         }
    1422                 :     }
    1423             116 : }
    1424                 : 
    1425                 : /************************************************************************/
    1426                 : /*                       SetFilteredClassName()                         */
    1427                 : /************************************************************************/
    1428                 : 
    1429             322 : int GMLReader::SetFilteredClassName(const char* pszClassName)
    1430                 : {
    1431             322 :     CPLFree(m_pszFilteredClassName);
    1432             322 :     m_pszFilteredClassName = (pszClassName) ? CPLStrdup(pszClassName) : NULL;
    1433             322 :     return TRUE;
    1434                 : }

Generated by: LCOV version 1.7