LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/nas - nasreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 361 289 80.1 %
Date: 2012-04-28 Functions: 31 24 77.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: nasreader.cpp 24105 2012-03-10 12:08:04Z rouault $
       3                 :  *
       4                 :  * Project:  NAS Reader
       5                 :  * Purpose:  Implementation of NASReader 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                 : 
      35                 : #define SUPPORT_GEOMETRY
      36                 : 
      37                 : #ifdef SUPPORT_GEOMETRY
      38                 : #  include "ogr_geometry.h"
      39                 : #endif
      40                 : 
      41                 : /************************************************************************/
      42                 : /* ==================================================================== */
      43                 : /*                  With XERCES Library                                 */
      44                 : /* ==================================================================== */
      45                 : /************************************************************************/
      46                 : 
      47                 : #include "nasreaderp.h"
      48                 : #include "cpl_conv.h"
      49                 : 
      50                 : /************************************************************************/
      51                 : /*                          CreateGMLReader()                           */
      52                 : /************************************************************************/
      53                 : 
      54              10 : IGMLReader *CreateNASReader()
      55                 : 
      56                 : {
      57              10 :     return new NASReader();
      58                 : }
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                             GMLReader()                              */
      62                 : /************************************************************************/
      63                 : 
      64              10 : NASReader::NASReader()
      65                 : 
      66                 : {
      67              10 :     m_nClassCount = 0;
      68              10 :     m_papoClass = NULL;
      69                 : 
      70              10 :     m_bClassListLocked = FALSE;
      71                 : 
      72              10 :     m_poNASHandler = NULL;
      73              10 :     m_poSAXReader = NULL;
      74              10 :     m_bReadStarted = FALSE;
      75                 :     
      76              10 :     m_poState = NULL;
      77              10 :     m_poCompleteFeature = NULL;
      78                 : 
      79              10 :     m_pszFilename = NULL;
      80              10 :     m_pszFilteredClassName = NULL;
      81              10 : }
      82                 : 
      83                 : /************************************************************************/
      84                 : /*                             ~NASReader()                             */
      85                 : /************************************************************************/
      86                 : 
      87              10 : NASReader::~NASReader()
      88                 : 
      89                 : {
      90              10 :     ClearClasses();
      91                 : 
      92              10 :     CPLFree( m_pszFilename );
      93                 : 
      94              10 :     CleanupParser();
      95                 : 
      96              10 :     if (CSLTestBoolean(CPLGetConfigOption("NAS_XERCES_TERMINATE", "FALSE")))
      97               0 :         XMLPlatformUtils::Terminate();
      98                 : 
      99              10 :     CPLFree( m_pszFilteredClassName );
     100              10 : }
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                          SetSourceFile()                             */
     104                 : /************************************************************************/
     105                 : 
     106              10 : void NASReader::SetSourceFile( const char *pszFilename )
     107                 : 
     108                 : {
     109              10 :     CPLFree( m_pszFilename );
     110              10 :     m_pszFilename = CPLStrdup( pszFilename );
     111              10 : }
     112                 : 
     113                 : /************************************************************************/
     114                 : /*                       GetSourceFileName()                            */
     115                 : /************************************************************************/
     116                 : 
     117               0 : const char* NASReader::GetSourceFileName()
     118                 : 
     119                 : {
     120               0 :     return m_pszFilename;
     121                 : }
     122                 : 
     123                 : /************************************************************************/
     124                 : /*                            SetupParser()                             */
     125                 : /************************************************************************/
     126                 : 
     127              18 : int NASReader::SetupParser()
     128                 : 
     129                 : {
     130                 :     static int bXercesInitialized = FALSE;
     131                 : 
     132              18 :     if( !bXercesInitialized )
     133                 :     {
     134                 :         try
     135                 :         {
     136               2 :             XMLPlatformUtils::Initialize();
     137                 :         }
     138                 :         
     139               0 :         catch (const XMLException& toCatch)
     140                 :         {
     141                 :             CPLError( CE_Warning, CPLE_AppDefined,
     142                 :                       "Exception initializing Xerces based GML reader.\n%s", 
     143               0 :                       tr_strdup(toCatch.getMessage()) );
     144               0 :             return FALSE;
     145                 :         }
     146               2 :         bXercesInitialized = TRUE;
     147                 :     }
     148                 : 
     149                 :     // Cleanup any old parser.
     150              18 :     if( m_poSAXReader != NULL )
     151               0 :         CleanupParser();
     152                 : 
     153                 :     // Create and initialize parser.
     154              18 :     XMLCh* xmlUriValid = NULL;
     155              18 :     XMLCh* xmlUriNS = NULL;
     156                 : 
     157                 :     try{
     158              18 :         m_poSAXReader = XMLReaderFactory::createXMLReader();
     159                 :     
     160              18 :         m_poNASHandler = new NASHandler( this );
     161                 : 
     162              36 :         m_poSAXReader->setContentHandler( m_poNASHandler );
     163              18 :         m_poSAXReader->setErrorHandler( m_poNASHandler );
     164              18 :         m_poSAXReader->setLexicalHandler( m_poNASHandler );
     165              18 :         m_poSAXReader->setEntityResolver( m_poNASHandler );
     166              18 :         m_poSAXReader->setDTDHandler( m_poNASHandler );
     167                 : 
     168              18 :         xmlUriValid = XMLString::transcode("http://xml.org/sax/features/validation");
     169              18 :         xmlUriNS = XMLString::transcode("http://xml.org/sax/features/namespaces");
     170                 : 
     171                 : #if (OGR_GML_VALIDATION)
     172                 :         m_poSAXReader->setFeature( xmlUriValid, true);
     173                 :         m_poSAXReader->setFeature( xmlUriNS, true);
     174                 : 
     175                 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
     176                 :         m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
     177                 : 
     178                 : //    m_poSAXReader->setDoSchema(true);
     179                 : //    m_poSAXReader->setValidationSchemaFullChecking(true);
     180                 : #else
     181              18 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreValidation, false);
     182                 : 
     183                 : #if XERCES_VERSION_MAJOR >= 3
     184                 :         m_poSAXReader->setFeature( XMLUni::fgXercesSchema, false);
     185                 : #else
     186              18 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, false);
     187                 : #endif
     188                 : 
     189                 : #endif
     190              18 :         XMLString::release( &xmlUriValid );
     191              18 :         XMLString::release( &xmlUriNS );
     192                 :     }
     193               0 :     catch (...)
     194                 :     {
     195               0 :         XMLString::release( &xmlUriValid );
     196               0 :         XMLString::release( &xmlUriNS );
     197                 : 
     198                 :         CPLError( CE_Warning, CPLE_AppDefined,
     199               0 :                   "Exception initializing Xerces based GML reader.\n" );
     200               0 :         return FALSE;
     201                 :     }
     202                 : 
     203              18 :     m_bReadStarted = FALSE;
     204                 : 
     205                 :     // Push an empty state.
     206              36 :     PushState( new GMLReadState() );
     207                 : 
     208              18 :     return TRUE;
     209                 : }
     210                 : 
     211                 : /************************************************************************/
     212                 : /*                           CleanupParser()                            */
     213                 : /************************************************************************/
     214                 : 
     215              34 : void NASReader::CleanupParser()
     216                 : 
     217                 : {
     218              34 :     if( m_poSAXReader == NULL )
     219              16 :         return;
     220                 : 
     221              54 :     while( m_poState )
     222              18 :         PopState();
     223                 : 
     224              18 :     delete m_poSAXReader;
     225              18 :     m_poSAXReader = NULL;
     226                 : 
     227              18 :     delete m_poNASHandler;
     228              18 :     m_poNASHandler = NULL;
     229                 : 
     230              18 :     delete m_poCompleteFeature;
     231              18 :     m_poCompleteFeature = NULL;
     232                 : 
     233              18 :     m_bReadStarted = FALSE;
     234                 : }
     235                 : 
     236                 : /************************************************************************/
     237                 : /*                            NextFeature()                             */
     238                 : /************************************************************************/
     239                 : 
     240           17476 : GMLFeature *NASReader::NextFeature()
     241                 : 
     242                 : {
     243           17476 :     GMLFeature *poReturn = NULL;
     244                 : 
     245                 :     try
     246                 :     {
     247           17476 :         if( !m_bReadStarted )
     248                 :         {
     249              18 :             if( m_poSAXReader == NULL )
     250              12 :                 SetupParser();
     251                 : 
     252              18 :             if( !m_poSAXReader->parseFirst( m_pszFilename, m_oToFill ) )
     253               0 :                 return NULL;
     254              18 :             m_bReadStarted = TRUE;
     255                 :         }
     256                 : 
     257        35322204 :         while( m_poCompleteFeature == NULL 
     258        17652368 :                && m_poSAXReader->parseNext( m_oToFill ) ) {}
     259                 : 
     260           17476 :         poReturn = m_poCompleteFeature;
     261           17476 :         m_poCompleteFeature = NULL;
     262                 : 
     263                 :     }
     264               0 :     catch (const XMLException& toCatch)
     265                 :     {
     266                 :         CPLDebug( "NAS", 
     267                 :                   "Error during NextFeature()! Message:\n%s", 
     268               0 :                   tr_strdup( toCatch.getMessage() ) );
     269                 :     }
     270                 : 
     271           17476 :     return poReturn;
     272                 : }
     273                 : 
     274                 : /************************************************************************/
     275                 : /*                            PushFeature()                             */
     276                 : /*                                                                      */
     277                 : /*      Create a feature based on the named element.  If the            */
     278                 : /*      corresponding feature class doesn't exist yet, then create      */
     279                 : /*      it now.  A new GMLReadState will be created for the feature,    */
     280                 : /*      and it will be placed within that state.  The state is          */
     281                 : /*      pushed onto the readstate stack.                                */
     282                 : /************************************************************************/
     283                 : 
     284           17468 : void NASReader::PushFeature( const char *pszElement, 
     285                 :                              const Attributes &attrs )
     286                 : 
     287                 : {
     288                 :     int iClass;
     289                 : 
     290                 : /* -------------------------------------------------------------------- */
     291                 : /*      Find the class of this element.                                 */
     292                 : /* -------------------------------------------------------------------- */
     293          300070 :     for( iClass = 0; iClass < GetClassCount(); iClass++ )
     294                 :     {
     295          300064 :         if( EQUAL(pszElement,GetClass(iClass)->GetElementName()) )
     296           17462 :             break;
     297                 :     }
     298                 : 
     299                 : /* -------------------------------------------------------------------- */
     300                 : /*      Create a new feature class for this element, if there is no     */
     301                 : /*      existing class for it.                                          */
     302                 : /* -------------------------------------------------------------------- */
     303           17468 :     if( iClass == GetClassCount() )
     304                 :     {
     305               6 :         CPLAssert( !IsClassListLocked() );
     306                 : 
     307               6 :         GMLFeatureClass *poNewClass = new GMLFeatureClass( pszElement );
     308                 : 
     309               6 :         iClass = AddClass( poNewClass );
     310                 :     }
     311                 : 
     312                 : /* -------------------------------------------------------------------- */
     313                 : /*      Create a feature of this feature class.                         */
     314                 : /* -------------------------------------------------------------------- */
     315           17468 :     GMLFeature *poFeature = new GMLFeature( GetClass( iClass ) );
     316                 : 
     317                 : /* -------------------------------------------------------------------- */
     318                 : /*      Create and push a new read state.                               */
     319                 : /* -------------------------------------------------------------------- */
     320                 :     GMLReadState *poState;
     321                 : 
     322           34936 :     poState = new GMLReadState();
     323           17468 :     poState->m_poFeature = poFeature;
     324           17468 :     PushState( poState );
     325                 : 
     326                 : /* -------------------------------------------------------------------- */
     327                 : /*      Check for gml:id, and if found push it as an attribute named    */
     328                 : /*      gml_id.                                                         */
     329                 : /* -------------------------------------------------------------------- */
     330                 :     int nFIDIndex;
     331                 :     XMLCh   anFID[100];
     332                 : 
     333           17468 :     tr_strcpy( anFID, "gml:id" );
     334           17468 :     nFIDIndex = attrs.getIndex( anFID );
     335           17468 :     if( nFIDIndex != -1 )
     336                 :     {
     337           17456 :         char *pszFID = tr_strdup( attrs.getValue( nFIDIndex ) );
     338           17456 :         SetFeaturePropertyDirectly( "gml_id", pszFID );
     339                 :     }
     340                 : 
     341           17468 : }
     342                 : 
     343                 : /************************************************************************/
     344                 : /*                          IsFeatureElement()                          */
     345                 : /*                                                                      */
     346                 : /*      Based on context and the element name, is this element a new    */
     347                 : /*      GML feature element?                                            */
     348                 : /************************************************************************/
     349                 : 
     350          447254 : int NASReader::IsFeatureElement( const char *pszElement )
     351                 : 
     352                 : {
     353          447254 :     CPLAssert( m_poState != NULL );
     354                 : 
     355          447254 :     const char *pszLast = m_poState->GetLastComponent();
     356          447254 :     int        nLen = strlen(pszLast);
     357                 : 
     358                 :     // There seem to be two major NAS classes of feature identifiers 
     359                 :     // -- either a wfs:Insert or a gml:featureMember. 
     360                 : 
     361          447254 :     if( (nLen < 6 || !EQUAL(pszLast+nLen-6,"Insert")) 
     362                 :         && (nLen < 13 || !EQUAL(pszLast+nLen-13,"featureMember"))
     363                 :         && (nLen < 7 || !EQUAL(pszLast+nLen-7,"Replace")) )
     364          307962 :         return FALSE;
     365                 : 
     366                 :     // If the class list isn't locked, any element that is a featureMember
     367                 :     // will do. 
     368          139292 :     if( !IsClassListLocked() )
     369               6 :         return TRUE;
     370                 : 
     371                 :     // otherwise, find a class with the desired element name.
     372         2181606 :     for( int i = 0; i < GetClassCount(); i++ )
     373                 :     {
     374         2181606 :         if( EQUAL(pszElement,GetClass(i)->GetElementName()) )
     375          139286 :             return TRUE;
     376                 :     }
     377                 : 
     378               0 :     return FALSE;
     379                 : }
     380                 : 
     381                 : /************************************************************************/
     382                 : /*                         IsAttributeElement()                         */
     383                 : /************************************************************************/
     384                 : 
     385          307948 : int NASReader::IsAttributeElement( const char *pszElement )
     386                 : 
     387                 : {
     388          307948 :     if( m_poState->m_poFeature == NULL )
     389          139698 :         return FALSE;
     390                 : 
     391          168250 :     GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
     392                 : 
     393                 :     // If the schema is not yet locked, then any simple element
     394                 :     // is potentially an attribute.
     395          168250 :     if( !poClass->IsSchemaLocked() )
     396             224 :         return TRUE;
     397                 : 
     398                 :     // Otherwise build the path to this element into a single string
     399                 :     // and compare against known attributes.
     400          168026 :     CPLString osElemPath;
     401                 : 
     402          168026 :     if( m_poState->m_nPathLength == 0 )
     403           84440 :         osElemPath = pszElement;
     404                 :     else
     405                 :     {
     406           83586 :         osElemPath = m_poState->osPath;
     407           83586 :         osElemPath += "|";
     408           83586 :         osElemPath += pszElement;
     409                 :     }
     410                 : 
     411         1207544 :     for( int i = 0; i < poClass->GetPropertyCount(); i++ )
     412         1116452 :         if( EQUAL(poClass->GetProperty(i)->GetSrcElement(),osElemPath) )
     413           76934 :             return TRUE;
     414                 : 
     415           91092 :     return FALSE;
     416                 : }
     417                 : 
     418                 : /************************************************************************/
     419                 : /*                              PopState()                              */
     420                 : /************************************************************************/
     421                 : 
     422           17486 : void NASReader::PopState()
     423                 : 
     424                 : {
     425           17486 :     if( m_poState != NULL )
     426                 :     {
     427           17486 :         if( m_poState->m_poFeature != NULL && m_poCompleteFeature == NULL )
     428                 :         {
     429           17468 :             m_poCompleteFeature = m_poState->m_poFeature;
     430           17468 :             m_poState->m_poFeature = NULL;
     431                 :         }
     432                 : 
     433                 :         GMLReadState *poParent;
     434                 : 
     435           17486 :         poParent = m_poState->m_poParentState;
     436                 :         
     437           17486 :         delete m_poState;
     438           17486 :         m_poState = poParent;
     439                 :     }
     440           17486 : }
     441                 : 
     442                 : /************************************************************************/
     443                 : /*                             PushState()                              */
     444                 : /************************************************************************/
     445                 : 
     446           17486 : void NASReader::PushState( GMLReadState *poState )
     447                 : 
     448                 : {
     449           17486 :     poState->m_poParentState = m_poState;
     450           17486 :     m_poState = poState;
     451           17486 : }
     452                 : 
     453                 : /************************************************************************/
     454                 : /*                              GetClass()                              */
     455                 : /************************************************************************/
     456                 : 
     457         2516974 : GMLFeatureClass *NASReader::GetClass( int iClass ) const
     458                 : 
     459                 : {
     460         2516974 :     if( iClass < 0 || iClass >= m_nClassCount )
     461               0 :         return NULL;
     462                 :     else
     463         2516974 :         return m_papoClass[iClass];
     464                 : }
     465                 : 
     466                 : /************************************************************************/
     467                 : /*                              GetClass()                              */
     468                 : /************************************************************************/
     469                 : 
     470             508 : GMLFeatureClass *NASReader::GetClass( const char *pszName ) const
     471                 : 
     472                 : {
     473           17576 :     for( int iClass = 0; iClass < m_nClassCount; iClass++ )
     474                 :     {
     475           17322 :         if( EQUAL(GetClass(iClass)->GetName(),pszName) )
     476             254 :             return GetClass(iClass);
     477                 :     }
     478                 : 
     479             254 :     return NULL;
     480                 : }
     481                 : 
     482                 : /************************************************************************/
     483                 : /*                              AddClass()                              */
     484                 : /************************************************************************/
     485                 : 
     486             254 : int NASReader::AddClass( GMLFeatureClass *poNewClass )
     487                 : 
     488                 : {
     489             254 :     CPLAssert( GetClass( poNewClass->GetName() ) == NULL );
     490                 : 
     491             254 :     m_nClassCount++;
     492                 :     m_papoClass = (GMLFeatureClass **) 
     493             254 :         CPLRealloc( m_papoClass, sizeof(void*) * m_nClassCount );
     494                 : 
     495                 :     // keep delete the last entry
     496             254 :     if( m_nClassCount > 1 && EQUAL( m_papoClass[m_nClassCount-2]->GetName(), "Delete" ) )
     497                 :     {
     498               0 :       m_papoClass[m_nClassCount-1] = m_papoClass[m_nClassCount-2];
     499               0 :       m_papoClass[m_nClassCount-2] = poNewClass;
     500               0 :       return m_nClassCount-2;
     501                 :     }
     502                 :     else
     503                 :     {
     504             254 :       m_papoClass[m_nClassCount-1] = poNewClass;
     505             254 :       return m_nClassCount-1;
     506                 :     }
     507                 : }
     508                 : 
     509                 : /************************************************************************/
     510                 : /*                            ClearClasses()                            */
     511                 : /************************************************************************/
     512                 : 
     513              16 : void NASReader::ClearClasses()
     514                 : 
     515                 : {
     516             270 :     for( int i = 0; i < m_nClassCount; i++ )
     517             254 :         delete m_papoClass[i];
     518              16 :     CPLFree( m_papoClass );
     519                 : 
     520              16 :     m_nClassCount = 0;
     521              16 :     m_papoClass = NULL;
     522              16 : }
     523                 : 
     524                 : /************************************************************************/
     525                 : /*                         SetFeatureProperty()                         */
     526                 : /*                                                                      */
     527                 : /*      Set the property value on the current feature, adding the       */
     528                 : /*      property name to the GMLFeatureClass if required.               */
     529                 : /*      The pszValue ownership is passed to this function.              */
     530                 : /************************************************************************/
     531                 : 
     532           94546 : void NASReader::SetFeaturePropertyDirectly( const char *pszElement,
     533                 :                                             char *pszValue )
     534                 : 
     535                 : {
     536           94546 :     GMLFeature *poFeature = GetState()->m_poFeature;
     537                 : 
     538           94546 :     CPLAssert( poFeature  != NULL );
     539                 : 
     540                 : /* -------------------------------------------------------------------- */
     541                 : /*      Does this property exist in the feature class?  If not, add     */
     542                 : /*      it.                                                             */
     543                 : /* -------------------------------------------------------------------- */
     544           94546 :     GMLFeatureClass *poClass = poFeature->GetClass();
     545                 :     int      iProperty;
     546                 : 
     547          403716 :     for( iProperty=0; iProperty < poClass->GetPropertyCount(); iProperty++ )
     548                 :     {
     549          403650 :         if( EQUAL(poClass->GetProperty( iProperty )->GetSrcElement(),
     550                 :                   pszElement ) )
     551           94480 :             break;
     552                 :     }
     553                 :     
     554           94546 :     if( iProperty == poClass->GetPropertyCount() )
     555                 :     {
     556              66 :         if( poClass->IsSchemaLocked() )
     557                 :         {
     558               0 :             CPLDebug("NAS","Encountered property missing from class schema.");
     559               0 :             CPLFree(pszValue);
     560               0 :             return;
     561                 :         }
     562                 : 
     563              66 :         CPLString osFieldName;
     564                 :         
     565              66 :         if( strchr(pszElement,'|') == NULL )
     566              38 :             osFieldName = pszElement;
     567                 :         else
     568                 :         {
     569              28 :             osFieldName = strrchr(pszElement,'|') + 1;
     570              28 :             if( poClass->GetPropertyIndex(osFieldName) != -1 )
     571               4 :                 osFieldName = pszElement;
     572                 :         }
     573                 : 
     574                 :         // Does this conflict with an existing property name? 
     575             132 :         while( poClass->GetProperty(osFieldName) != NULL )
     576                 :         {
     577               0 :             osFieldName += "_";
     578                 :         }
     579                 : 
     580              66 :         GMLPropertyDefn *poPDefn = new GMLPropertyDefn(osFieldName,pszElement);
     581                 : 
     582             132 :         if( EQUAL(CPLGetConfigOption( "GML_FIELDTYPES", ""), "ALWAYS_STRING") )
     583               0 :             poPDefn->SetType( GMLPT_String );
     584                 : 
     585              66 :         poClass->AddProperty( poPDefn );
     586                 :     }
     587                 : 
     588                 : /* -------------------------------------------------------------------- */
     589                 : /*      We want to handle <lage> specially to ensure it is zero         */
     590                 : /*      filled, and treated as a string depspite the numeric            */
     591                 : /*      content. https://trac.wheregroup.com/PostNAS/ticket/9           */
     592                 : /* -------------------------------------------------------------------- */
     593           94546 :     if( strcmp(poClass->GetProperty(iProperty)->GetName(),"lage") == 0 )
     594                 :     {
     595             630 :         if( strlen(pszValue) < 5 )
     596                 :         {
     597               0 :             CPLString osValue = "00000";
     598               0 :             osValue += pszValue;
     599               0 :             poFeature->SetPropertyDirectly( iProperty, CPLStrdup(osValue + osValue.size() - 5) );
     600               0 :             CPLFree(pszValue);
     601                 :         }
     602                 :         else
     603             630 :             poFeature->SetPropertyDirectly( iProperty, pszValue );
     604                 : 
     605                 :         
     606             630 :         if( !poClass->IsSchemaLocked() )
     607                 :         {
     608               0 :             poClass->GetProperty(iProperty)->SetWidth( 5 );
     609               0 :             poClass->GetProperty(iProperty)->SetType( GMLPT_String );
     610                 :         }
     611             630 :         return;
     612                 :     }
     613                 : 
     614                 : /* -------------------------------------------------------------------- */
     615                 : /*      Set the property                                                */
     616                 : /* -------------------------------------------------------------------- */
     617           93916 :     poFeature->SetPropertyDirectly( iProperty, pszValue );
     618                 : 
     619                 : /* -------------------------------------------------------------------- */
     620                 : /*      Do we need to update the property type?                         */
     621                 : /* -------------------------------------------------------------------- */
     622           93916 :     if( !poClass->IsSchemaLocked() )
     623                 :     {
     624                 :         // Special handling for punktkennung per NAS #12
     625             160 :         if( strcmp(poClass->GetProperty(iProperty)->GetName(),
     626                 :                    "punktkennung") == 0)
     627                 :         {
     628               0 :             poClass->GetProperty(iProperty)->SetWidth( 15 );
     629               0 :             poClass->GetProperty(iProperty)->SetType( GMLPT_String );
     630                 :         }
     631                 :         // Special handling for artDerFlurstuecksgrenze per http://trac.osgeo.org/gdal/ticket/4255
     632             160 :         else if( strcmp(poClass->GetProperty(iProperty)->GetName(),
     633                 :                    "artDerFlurstuecksgrenze") == 0)
     634                 :         {
     635               0 :             poClass->GetProperty(iProperty)->SetType( GMLPT_IntegerList );
     636                 :         }
     637                 :         else
     638                 :             poClass->GetProperty(iProperty)->AnalysePropertyValue(
     639             160 :                 poFeature->GetProperty(iProperty));
     640                 :     }
     641                 : }
     642                 : 
     643                 : /************************************************************************/
     644                 : /*                            LoadClasses()                             */
     645                 : /************************************************************************/
     646                 : 
     647               4 : int NASReader::LoadClasses( const char *pszFile )
     648                 : 
     649                 : {
     650                 :     // Add logic later to determine reasonable default schema file. 
     651               4 :     if( pszFile == NULL )
     652               0 :         return FALSE;
     653                 : 
     654                 : /* -------------------------------------------------------------------- */
     655                 : /*      Load the raw XML file.                                          */
     656                 : /* -------------------------------------------------------------------- */
     657                 :     FILE       *fp;
     658                 :     int         nLength;
     659                 :     char        *pszWholeText;
     660                 : 
     661               4 :     fp = VSIFOpen( pszFile, "rb" );
     662                 : 
     663               4 :     if( fp == NULL )
     664                 :     {
     665                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     666               0 :                   "Failed to open file %s.", pszFile );
     667               0 :         return FALSE;
     668                 :     }
     669                 : 
     670               4 :     VSIFSeek( fp, 0, SEEK_END );
     671               4 :     nLength = VSIFTell( fp );
     672               4 :     VSIFSeek( fp, 0, SEEK_SET );
     673                 : 
     674               4 :     pszWholeText = (char *) VSIMalloc(nLength+1);
     675               4 :     if( pszWholeText == NULL )
     676                 :     {
     677                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     678                 :                   "Failed to allocate %d byte buffer for %s,\n"
     679                 :                   "is this really a GMLFeatureClassList file?",
     680               0 :                   nLength, pszFile );
     681               0 :         VSIFClose( fp );
     682               0 :         return FALSE;
     683                 :     }
     684                 :     
     685               4 :     if( VSIFRead( pszWholeText, nLength, 1, fp ) != 1 )
     686                 :     {
     687               0 :         VSIFree( pszWholeText );
     688               0 :         VSIFClose( fp );
     689                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     690               0 :                   "Read failed on %s.", pszFile );
     691               0 :         return FALSE;
     692                 :     }
     693               4 :     pszWholeText[nLength] = '\0';
     694                 : 
     695               4 :     VSIFClose( fp );
     696                 : 
     697               4 :     if( strstr( pszWholeText, "<GMLFeatureClassList>" ) == NULL )
     698                 :     {
     699               0 :         VSIFree( pszWholeText );
     700                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     701                 :                   "File %s does not contain a GMLFeatureClassList tree.",
     702               0 :                   pszFile );
     703               0 :         return FALSE;
     704                 :     }
     705                 : 
     706                 : /* -------------------------------------------------------------------- */
     707                 : /*      Convert to XML parse tree.                                      */
     708                 : /* -------------------------------------------------------------------- */
     709                 :     CPLXMLNode *psRoot;
     710                 : 
     711               4 :     psRoot = CPLParseXMLString( pszWholeText );
     712               4 :     VSIFree( pszWholeText );
     713                 : 
     714                 :     // We assume parser will report errors via CPL.
     715               4 :     if( psRoot == NULL )
     716               0 :         return FALSE;
     717                 : 
     718               4 :     if( psRoot->eType != CXT_Element 
     719                 :         || !EQUAL(psRoot->pszValue,"GMLFeatureClassList") )
     720                 :     {
     721               0 :         CPLDestroyXMLNode(psRoot);
     722                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     723                 :                   "File %s is not a GMLFeatureClassList document.",
     724               0 :                   pszFile );
     725               0 :         return FALSE;
     726                 :     }
     727                 : 
     728                 : /* -------------------------------------------------------------------- */
     729                 : /*      Extract feature classes for all definitions found.              */
     730                 : /* -------------------------------------------------------------------- */
     731                 :     CPLXMLNode *psThis;
     732                 : 
     733             252 :     for( psThis = psRoot->psChild; psThis != NULL; psThis = psThis->psNext )
     734                 :     {
     735             248 :         if( psThis->eType == CXT_Element 
     736                 :             && EQUAL(psThis->pszValue,"GMLFeatureClass") )
     737                 :         {
     738                 :             GMLFeatureClass   *poClass;
     739                 : 
     740             248 :             poClass = new GMLFeatureClass();
     741                 : 
     742             248 :             if( !poClass->InitializeFromXML( psThis ) )
     743                 :             {
     744               0 :                 delete poClass;
     745               0 :                 CPLDestroyXMLNode( psRoot );
     746               0 :                 return FALSE;
     747                 :             }
     748                 : 
     749             248 :             poClass->SetSchemaLocked( TRUE );
     750                 : 
     751             248 :             AddClass( poClass );
     752                 :         }
     753                 :     }
     754                 : 
     755               4 :     CPLDestroyXMLNode( psRoot );
     756                 :     
     757               4 :     SetClassListLocked( TRUE );
     758                 : 
     759               4 :     return TRUE;
     760                 : }
     761                 : 
     762                 : /************************************************************************/
     763                 : /*                            SaveClasses()                             */
     764                 : /************************************************************************/
     765                 : 
     766               4 : int NASReader::SaveClasses( const char *pszFile )
     767                 : 
     768                 : {
     769                 :     // Add logic later to determine reasonable default schema file. 
     770               4 :     if( pszFile == NULL )
     771               0 :         return FALSE;
     772                 : 
     773                 : /* -------------------------------------------------------------------- */
     774                 : /*      Create in memory schema tree.                                   */
     775                 : /* -------------------------------------------------------------------- */
     776                 :     CPLXMLNode *psRoot;
     777                 : 
     778               4 :     psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClassList" );
     779                 : 
     780              10 :     for( int iClass = 0; iClass < GetClassCount(); iClass++ )
     781                 :     {
     782               6 :         GMLFeatureClass *poClass = GetClass( iClass );
     783                 :         
     784               6 :         CPLAddXMLChild( psRoot, poClass->SerializeToXML() );
     785                 :     }
     786                 : 
     787                 : /* -------------------------------------------------------------------- */
     788                 : /*      Serialize to disk.                                              */
     789                 : /* -------------------------------------------------------------------- */
     790                 :     FILE        *fp;
     791               4 :     int         bSuccess = TRUE;
     792               4 :     char        *pszWholeText = CPLSerializeXMLTree( psRoot );
     793                 :     
     794               4 :     CPLDestroyXMLNode( psRoot );
     795                 :  
     796               4 :     fp = VSIFOpen( pszFile, "wb" );
     797                 :     
     798               4 :     if( fp == NULL )
     799               0 :         bSuccess = FALSE;
     800               4 :     else if( VSIFWrite( pszWholeText, strlen(pszWholeText), 1, fp ) != 1 )
     801               0 :         bSuccess = FALSE;
     802                 :     else
     803               4 :         VSIFClose( fp );
     804                 : 
     805               4 :     CPLFree( pszWholeText );
     806                 : 
     807               4 :     return bSuccess;
     808                 : }
     809                 : 
     810                 : /************************************************************************/
     811                 : /*                          PrescanForSchema()                          */
     812                 : /*                                                                      */
     813                 : /*      For now we use a pretty dumb approach of just doing a normal    */
     814                 : /*      scan of the whole file, building up the schema information.     */
     815                 : /*      Eventually we hope to do a more efficient scan when just        */
     816                 : /*      looking for schema information.                                 */
     817                 : /************************************************************************/
     818                 : 
     819               6 : int NASReader::PrescanForSchema( int bGetExtents )
     820                 : 
     821                 : {
     822                 :     GMLFeature  *poFeature;
     823                 : 
     824               6 :     if( m_pszFilename == NULL )
     825               0 :         return FALSE;
     826                 : 
     827               6 :     SetClassListLocked( FALSE );
     828                 : 
     829               6 :     ClearClasses();
     830               6 :     if( !SetupParser() )
     831               0 :         return FALSE;
     832                 : 
     833               6 :     std::string osWork;
     834                 : 
     835              22 :     while( (poFeature = NextFeature()) != NULL )
     836                 :     {
     837              10 :         GMLFeatureClass *poClass = poFeature->GetClass();
     838                 : 
     839              10 :         if( poClass->GetFeatureCount() == -1 )
     840               6 :             poClass->SetFeatureCount( 1 );
     841                 :         else
     842               4 :             poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
     843                 : 
     844                 : #ifdef SUPPORT_GEOMETRY
     845              10 :         if( bGetExtents )
     846                 :         {
     847              10 :             OGRGeometry *poGeometry = NULL;
     848                 : 
     849              10 :             const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList();
     850              10 :             if( papsGeometry[0] != NULL )
     851                 :             {
     852               2 :                 poGeometry = (OGRGeometry*) OGR_G_CreateFromGMLTree(papsGeometry[0]);
     853                 :             }
     854                 : 
     855              10 :             if( poGeometry != NULL )
     856                 :             {
     857                 :                 double  dfXMin, dfXMax, dfYMin, dfYMax;
     858               2 :                 OGREnvelope sEnvelope;
     859                 :                 OGRwkbGeometryType eGType = (OGRwkbGeometryType) 
     860               2 :                     poClass->GetGeometryType();
     861                 : 
     862                 :                 // Merge SRSName into layer.
     863               2 :                 const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork, FALSE);
     864                 : //                if (pszSRSName != NULL)
     865                 : //                    m_bCanUseGlobalSRSName = FALSE;
     866               2 :                 poClass->MergeSRSName(pszSRSName);
     867                 : 
     868                 :                 // Merge geometry type into layer.
     869               2 :                 if( poClass->GetFeatureCount() == 1 && eGType == wkbUnknown )
     870               2 :                     eGType = wkbNone;
     871                 : 
     872                 :                 poClass->SetGeometryType( 
     873                 :                     (int) OGRMergeGeometryTypes(
     874               2 :                         eGType, poGeometry->getGeometryType() ) );
     875                 : 
     876                 :                 // merge extents.
     877               2 :                 poGeometry->getEnvelope( &sEnvelope );
     878               2 :                 delete poGeometry;
     879               2 :                 if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
     880                 :                 {
     881               0 :                     dfXMin = MIN(dfXMin,sEnvelope.MinX);
     882               0 :                     dfXMax = MAX(dfXMax,sEnvelope.MaxX);
     883               0 :                     dfYMin = MIN(dfYMin,sEnvelope.MinY);
     884               0 :                     dfYMax = MAX(dfYMax,sEnvelope.MaxY);
     885                 :                 }
     886                 :                 else
     887                 :                 {
     888               2 :                     dfXMin = sEnvelope.MinX;
     889               2 :                     dfXMax = sEnvelope.MaxX;
     890               2 :                     dfYMin = sEnvelope.MinY;
     891               2 :                     dfYMax = sEnvelope.MaxY;
     892                 :                 }
     893                 : 
     894               2 :                 poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax );
     895                 :             }
     896                 :             else 
     897                 :             {
     898               8 :                 if( poClass->GetGeometryType() == (int) wkbUnknown 
     899                 :                     && poClass->GetFeatureCount() == 1 )
     900               4 :                     poClass->SetGeometryType( wkbNone );
     901                 :             }
     902                 : #endif /* def SUPPORT_GEOMETRY */
     903                 :         }
     904                 :         
     905              10 :         delete poFeature;
     906                 :     }
     907                 : 
     908               6 :     CleanupParser();
     909                 : 
     910               6 :     return GetClassCount() > 0;
     911                 : }
     912                 : 
     913                 : /************************************************************************/
     914                 : /*                            ResetReading()                            */
     915                 : /************************************************************************/
     916                 : 
     917              18 : void NASReader::ResetReading()
     918                 : 
     919                 : {
     920              18 :     CleanupParser();
     921              18 :     SetFilteredClassName(NULL);
     922              18 : }
     923                 : 
     924                 : /************************************************************************/
     925                 : /*                            CheckForFID()                             */
     926                 : /*                                                                      */
     927                 : /*      Merge the fid attribute into the current field text.            */
     928                 : /************************************************************************/
     929                 : 
     930              12 : void NASReader::CheckForFID( const Attributes &attrs,
     931                 :                              char **ppszCurField )
     932                 : 
     933                 : {
     934                 :     int nIndex;
     935                 :     XMLCh  Name[100];
     936                 : 
     937              12 :     tr_strcpy( Name, "fid" );
     938              12 :     nIndex = attrs.getIndex( Name );
     939                 : 
     940              12 :     if( nIndex != -1 )
     941                 :     {
     942              12 :         char *pszFID = tr_strdup( attrs.getValue( nIndex ) );
     943              12 :         CPLString osCurField = *ppszCurField;
     944                 : 
     945              12 :         osCurField += pszFID;
     946              12 :         CPLFree( pszFID );
     947                 : 
     948              12 :         CPLFree( *ppszCurField );
     949              12 :         *ppszCurField = CPLStrdup(osCurField);
     950                 :     }
     951              12 : }
     952                 : 
     953                 : /************************************************************************/
     954                 : /*                         CheckForRelations()                          */
     955                 : /************************************************************************/
     956                 : 
     957           77158 : void NASReader::CheckForRelations( const char *pszElement, 
     958                 :                                    const Attributes &attrs )
     959                 : 
     960                 : {
     961           77158 :     GMLFeature *poFeature = GetState()->m_poFeature;
     962                 : 
     963           77158 :     CPLAssert( poFeature  != NULL );
     964                 : 
     965                 :     int nIndex;
     966                 :     XMLCh  Name[100];
     967                 : 
     968           77158 :     tr_strcpy( Name, "xlink:href" );
     969           77158 :     nIndex = attrs.getIndex( Name );
     970                 : 
     971           77158 :     if( nIndex != -1 )
     972                 :     {
     973            5016 :         char *pszHRef = tr_strdup( attrs.getValue( nIndex ) );
     974                 : 
     975            5016 :         if( EQUALN(pszHRef,"urn:adv:oid:", 12 ) )
     976            5016 :             poFeature->AddOBProperty( pszElement, pszHRef );
     977                 : 
     978            5016 :         CPLFree( pszHRef );
     979                 :     }
     980           77158 : }
     981                 : 
     982                 : /************************************************************************/
     983                 : /*                         HugeFileResolver()                           */
     984                 : /*      Returns TRUE for success                                        */
     985                 : /************************************************************************/
     986                 : 
     987               0 : int NASReader::HugeFileResolver( const char *pszFile,
     988                 :                               int bSqliteIsTempFile,
     989                 :                               int iSqliteCacheMB )
     990                 : 
     991                 : {
     992               0 :     CPLDebug( "NAS", "HugeFileResolver() not currently implemented for NAS." );
     993               0 :     return FALSE;
     994                 : }
     995                 : 
     996                 : /************************************************************************/
     997                 : /*                         PrescanForTemplate()                         */
     998                 : /*      Returns TRUE for success                                        */
     999                 : /************************************************************************/
    1000                 : 
    1001               0 : int NASReader::PrescanForTemplate( void )
    1002                 : 
    1003                 : {
    1004               0 :     CPLDebug( "NAS", "PrescanForTemplate() not currently implemented for NAS." );
    1005               0 :     return FALSE;
    1006                 : }
    1007                 : 
    1008                 : /************************************************************************/
    1009                 : /*                           ResolveXlinks()                            */
    1010                 : /*      Returns TRUE for success                                        */
    1011                 : /************************************************************************/
    1012                 : 
    1013               0 : int NASReader::ResolveXlinks( const char *pszFile,
    1014                 :                               int* pbOutIsTempFile,
    1015                 :                               char **papszSkip,
    1016                 :                               const int bStrict )
    1017                 : 
    1018                 : {
    1019               0 :     CPLDebug( "NAS", "ResolveXlinks() not currently implemented for NAS." );
    1020               0 :     return FALSE;
    1021                 : }
    1022                 : 
    1023                 : /************************************************************************/
    1024                 : /*                       SetFilteredClassName()                         */
    1025                 : /************************************************************************/
    1026                 : 
    1027              34 : int NASReader::SetFilteredClassName(const char* pszClassName)
    1028                 : {
    1029              34 :     CPLFree(m_pszFilteredClassName);
    1030              34 :     m_pszFilteredClassName = (pszClassName) ? CPLStrdup(pszClassName) : NULL;
    1031              34 :     return TRUE;
    1032                 : }

Generated by: LCOV version 1.7