LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - gmlreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 538 398 74.0 %
Date: 2012-12-26 Functions: 49 29 59.2 %

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

Generated by: LCOV version 1.7