LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/nas - nasreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 373 298 79.9 %
Date: 2012-12-26 Functions: 31 24 77.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: nasreader.cpp 25120 2012-10-13 22:38:57Z 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               5 : IGMLReader *CreateNASReader()
      55                 : 
      56                 : {
      57               5 :     return new NASReader();
      58                 : }
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                             GMLReader()                              */
      62                 : /************************************************************************/
      63                 : 
      64               5 : NASReader::NASReader()
      65                 : 
      66                 : {
      67               5 :     m_nClassCount = 0;
      68               5 :     m_papoClass = NULL;
      69                 : 
      70               5 :     m_bClassListLocked = FALSE;
      71                 : 
      72               5 :     m_poNASHandler = NULL;
      73               5 :     m_poSAXReader = NULL;
      74               5 :     m_bReadStarted = FALSE;
      75                 :     
      76               5 :     m_poState = NULL;
      77               5 :     m_poCompleteFeature = NULL;
      78                 : 
      79               5 :     m_pszFilename = NULL;
      80               5 :     m_pszFilteredClassName = NULL;
      81               5 : }
      82                 : 
      83                 : /************************************************************************/
      84                 : /*                             ~NASReader()                             */
      85                 : /************************************************************************/
      86                 : 
      87               5 : NASReader::~NASReader()
      88                 : 
      89                 : {
      90               5 :     ClearClasses();
      91                 : 
      92               5 :     CPLFree( m_pszFilename );
      93                 : 
      94               5 :     CleanupParser();
      95                 : 
      96               5 :     if (CSLTestBoolean(CPLGetConfigOption("NAS_XERCES_TERMINATE", "FALSE")))
      97               0 :         XMLPlatformUtils::Terminate();
      98                 : 
      99               5 :     CPLFree( m_pszFilteredClassName );
     100               5 : }
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                          SetSourceFile()                             */
     104                 : /************************************************************************/
     105                 : 
     106               5 : void NASReader::SetSourceFile( const char *pszFilename )
     107                 : 
     108                 : {
     109               5 :     CPLFree( m_pszFilename );
     110               5 :     m_pszFilename = CPLStrdup( pszFilename );
     111               5 : }
     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               9 : int NASReader::SetupParser()
     128                 : 
     129                 : {
     130                 :     static int bXercesInitialized = FALSE;
     131                 : 
     132               9 :     if( !bXercesInitialized )
     133                 :     {
     134                 :         try
     135                 :         {
     136               1 :             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               1 :         bXercesInitialized = TRUE;
     147                 :     }
     148                 : 
     149                 :     // Cleanup any old parser.
     150               9 :     if( m_poSAXReader != NULL )
     151               0 :         CleanupParser();
     152                 : 
     153                 :     // Create and initialize parser.
     154               9 :     XMLCh* xmlUriValid = NULL;
     155               9 :     XMLCh* xmlUriNS = NULL;
     156                 : 
     157                 :     try{
     158               9 :         m_poSAXReader = XMLReaderFactory::createXMLReader();
     159                 :     
     160               9 :         m_poNASHandler = new NASHandler( this );
     161                 : 
     162              18 :         m_poSAXReader->setContentHandler( m_poNASHandler );
     163               9 :         m_poSAXReader->setErrorHandler( m_poNASHandler );
     164               9 :         m_poSAXReader->setLexicalHandler( m_poNASHandler );
     165               9 :         m_poSAXReader->setEntityResolver( m_poNASHandler );
     166               9 :         m_poSAXReader->setDTDHandler( m_poNASHandler );
     167                 : 
     168               9 :         xmlUriValid = XMLString::transcode("http://xml.org/sax/features/validation");
     169               9 :         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               9 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreValidation, false);
     182                 : 
     183                 : #if XERCES_VERSION_MAJOR >= 3
     184                 :         m_poSAXReader->setFeature( XMLUni::fgXercesSchema, false);
     185                 : #else
     186               9 :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, false);
     187                 : #endif
     188                 : 
     189                 : #endif
     190               9 :         XMLString::release( &xmlUriValid );
     191               9 :         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               9 :     m_bReadStarted = FALSE;
     204                 : 
     205                 :     // Push an empty state.
     206              18 :     PushState( new GMLReadState() );
     207                 : 
     208               9 :     return TRUE;
     209                 : }
     210                 : 
     211                 : /************************************************************************/
     212                 : /*                           CleanupParser()                            */
     213                 : /************************************************************************/
     214                 : 
     215              17 : void NASReader::CleanupParser()
     216                 : 
     217                 : {
     218              17 :     if( m_poSAXReader == NULL )
     219               8 :         return;
     220                 : 
     221              27 :     while( m_poState )
     222               9 :         PopState();
     223                 : 
     224               9 :     delete m_poSAXReader;
     225               9 :     m_poSAXReader = NULL;
     226                 : 
     227               9 :     delete m_poNASHandler;
     228               9 :     m_poNASHandler = NULL;
     229                 : 
     230               9 :     delete m_poCompleteFeature;
     231               9 :     m_poCompleteFeature = NULL;
     232                 : 
     233               9 :     m_bReadStarted = FALSE;
     234                 : }
     235                 : 
     236                 : /************************************************************************/
     237                 : /*                            NextFeature()                             */
     238                 : /************************************************************************/
     239                 : 
     240            8738 : GMLFeature *NASReader::NextFeature()
     241                 : 
     242                 : {
     243            8738 :     GMLFeature *poReturn = NULL;
     244                 : 
     245                 :     try
     246                 :     {
     247            8738 :         if( !m_bReadStarted )
     248                 :         {
     249               9 :             if( m_poSAXReader == NULL )
     250               6 :                 SetupParser();
     251                 : 
     252               9 :             if( !m_poSAXReader->parseFirst( m_pszFilename, m_oToFill ) )
     253               0 :                 return NULL;
     254               9 :             m_bReadStarted = TRUE;
     255                 :         }
     256                 : 
     257        17661102 :         while( m_poCompleteFeature == NULL 
     258         8826184 :                && m_poSAXReader->parseNext( m_oToFill ) ) {}
     259                 : 
     260            8738 :         poReturn = m_poCompleteFeature;
     261            8738 :         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            8738 :     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            8734 : 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          150035 :     for( iClass = 0; iClass < GetClassCount(); iClass++ )
     294                 :     {
     295          150032 :         if( EQUAL(pszElement,GetClass(iClass)->GetElementName()) )
     296            8731 :             break;
     297                 :     }
     298                 : 
     299                 : /* -------------------------------------------------------------------- */
     300                 : /*      Create a new feature class for this element, if there is no     */
     301                 : /*      existing class for it.                                          */
     302                 : /* -------------------------------------------------------------------- */
     303            8734 :     if( iClass == GetClassCount() )
     304                 :     {
     305               3 :         CPLAssert( !IsClassListLocked() );
     306                 : 
     307               3 :         GMLFeatureClass *poNewClass = new GMLFeatureClass( pszElement );
     308                 : 
     309               3 :         iClass = AddClass( poNewClass );
     310                 :     }
     311                 : 
     312                 : /* -------------------------------------------------------------------- */
     313                 : /*      Create a feature of this feature class.                         */
     314                 : /* -------------------------------------------------------------------- */
     315            8734 :     GMLFeature *poFeature = new GMLFeature( GetClass( iClass ) );
     316                 : 
     317                 : /* -------------------------------------------------------------------- */
     318                 : /*      Create and push a new read state.                               */
     319                 : /* -------------------------------------------------------------------- */
     320                 :     GMLReadState *poState;
     321                 : 
     322           17468 :     poState = new GMLReadState();
     323            8734 :     poState->m_poFeature = poFeature;
     324            8734 :     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            8734 :     tr_strcpy( anFID, "gml:id" );
     334            8734 :     nFIDIndex = attrs.getIndex( anFID );
     335            8734 :     if( nFIDIndex != -1 )
     336                 :     {
     337            8728 :         char *pszFID = tr_strdup( attrs.getValue( nFIDIndex ) );
     338            8728 :         SetFeaturePropertyDirectly( "gml_id", pszFID );
     339                 :     }
     340                 : 
     341            8734 : }
     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          221593 : int NASReader::IsFeatureElement( const char *pszElement )
     351                 : 
     352                 : {
     353          221593 :     CPLAssert( m_poState != NULL );
     354                 : 
     355          221593 :     const char *pszLast = m_poState->GetLastComponent();
     356          221593 :     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          221593 :     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          151947 :         return FALSE;
     365                 : 
     366                 :     // If the class list isn't locked, any element that is a featureMember
     367                 :     // will do.
     368           69646 :     if( !IsClassListLocked() )
     369               3 :         return TRUE;
     370                 : 
     371                 :     // otherwise, find a class with the desired element name.
     372         1090803 :     for( int i = 0; i < GetClassCount(); i++ )
     373                 :     {
     374         1090803 :         if( EQUAL(pszElement,GetClass(i)->GetElementName()) )
     375           69643 :             return TRUE;
     376                 :     }
     377                 : 
     378               0 :     return FALSE;
     379                 : }
     380                 : 
     381                 : /************************************************************************/
     382                 : /*                         IsAttributeElement()                         */
     383                 : /************************************************************************/
     384                 : 
     385          151940 : int NASReader::IsAttributeElement( const char *pszElement )
     386                 : 
     387                 : {
     388          151940 :     if( m_poState->m_poFeature == NULL )
     389           69849 :         return FALSE;
     390                 : 
     391           82091 :     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           82091 :     if( !poClass->IsSchemaLocked() )
     396              76 :         return TRUE;
     397                 : 
     398                 :     // Otherwise build the path to this element into a single string
     399                 :     // and compare against known attributes.
     400           82015 :     CPLString osElemPath;
     401                 : 
     402           82015 :     if( m_poState->m_nPathLength == 0 )
     403           41887 :         osElemPath = pszElement;
     404                 :     else
     405                 :     {
     406           40128 :         osElemPath = m_poState->osPath;
     407           40128 :         osElemPath += "|";
     408           40128 :         osElemPath += pszElement;
     409                 :     }
     410                 : 
     411          566143 :     for( int i = 0; i < poClass->GetPropertyCount(); i++ )
     412          521929 :         if( EQUAL(poClass->GetProperty(i)->GetSrcElement(),osElemPath) )
     413           37801 :             return TRUE;
     414                 : 
     415           44214 :     return FALSE;
     416                 : }
     417                 : 
     418                 : /************************************************************************/
     419                 : /*                              PopState()                              */
     420                 : /************************************************************************/
     421                 : 
     422            8743 : void NASReader::PopState()
     423                 : 
     424                 : {
     425            8743 :     if( m_poState != NULL )
     426                 :     {
     427            8743 :         if( m_poState->m_poFeature != NULL && m_poCompleteFeature == NULL )
     428                 :         {
     429            8734 :             m_poCompleteFeature = m_poState->m_poFeature;
     430            8734 :             m_poState->m_poFeature = NULL;
     431                 :         }
     432                 : 
     433                 :         GMLReadState *poParent;
     434                 : 
     435            8743 :         poParent = m_poState->m_poParentState;
     436                 : 
     437            8743 :         delete m_poState;
     438            8743 :         m_poState = poParent;
     439                 :     }
     440            8743 : }
     441                 : 
     442                 : /************************************************************************/
     443                 : /*                             PushState()                              */
     444                 : /************************************************************************/
     445                 : 
     446            8743 : void NASReader::PushState( GMLReadState *poState )
     447                 : 
     448                 : {
     449            8743 :     poState->m_poParentState = m_poState;
     450            8743 :     m_poState = poState;
     451            8743 : }
     452                 : 
     453                 : /************************************************************************/
     454                 : /*                              GetClass()                              */
     455                 : /************************************************************************/
     456                 : 
     457         1258487 : GMLFeatureClass *NASReader::GetClass( int iClass ) const
     458                 : 
     459                 : {
     460         1258487 :     if( iClass < 0 || iClass >= m_nClassCount )
     461               0 :         return NULL;
     462                 :     else
     463         1258487 :         return m_papoClass[iClass];
     464                 : }
     465                 : 
     466                 : /************************************************************************/
     467                 : /*                              GetClass()                              */
     468                 : /************************************************************************/
     469                 : 
     470             254 : GMLFeatureClass *NASReader::GetClass( const char *pszName ) const
     471                 : 
     472                 : {
     473            8788 :     for( int iClass = 0; iClass < m_nClassCount; iClass++ )
     474                 :     {
     475            8661 :         if( EQUAL(GetClass(iClass)->GetName(),pszName) )
     476             127 :             return GetClass(iClass);
     477                 :     }
     478                 : 
     479             127 :     return NULL;
     480                 : }
     481                 : 
     482                 : /************************************************************************/
     483                 : /*                              AddClass()                              */
     484                 : /************************************************************************/
     485                 : 
     486             127 : int NASReader::AddClass( GMLFeatureClass *poNewClass )
     487                 : 
     488                 : {
     489             127 :     CPLAssert( GetClass( poNewClass->GetName() ) == NULL );
     490                 : 
     491             127 :     m_nClassCount++;
     492                 :     m_papoClass = (GMLFeatureClass **)
     493             127 :         CPLRealloc( m_papoClass, sizeof(void*) * m_nClassCount );
     494                 : 
     495                 :     // keep delete the last entry
     496             127 :     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             127 :       m_papoClass[m_nClassCount-1] = poNewClass;
     505             127 :       return m_nClassCount-1;
     506                 :     }
     507                 : }
     508                 : 
     509                 : /************************************************************************/
     510                 : /*                            ClearClasses()                            */
     511                 : /************************************************************************/
     512                 : 
     513               8 : void NASReader::ClearClasses()
     514                 : 
     515                 : {
     516             135 :     for( int i = 0; i < m_nClassCount; i++ )
     517             127 :         delete m_papoClass[i];
     518               8 :     CPLFree( m_papoClass );
     519                 : 
     520               8 :     m_nClassCount = 0;
     521               8 :     m_papoClass = NULL;
     522               8 : }
     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           46595 : void NASReader::SetFeaturePropertyDirectly( const char *pszElement,
     533                 :                                             char *pszValue )
     534                 : 
     535                 : {
     536           46595 :     GMLFeature *poFeature = GetState()->m_poFeature;
     537                 : 
     538           46595 :     CPLAssert( poFeature  != NULL );
     539                 : 
     540                 : /* -------------------------------------------------------------------- */
     541                 : /*      Does this property exist in the feature class?  If not, add     */
     542                 : /*      it.                                                             */
     543                 : /* -------------------------------------------------------------------- */
     544           46595 :     GMLFeatureClass *poClass = poFeature->GetClass();
     545                 :     int      iProperty;
     546                 : 
     547          197341 :     for( iProperty=0; iProperty < poClass->GetPropertyCount(); iProperty++ )
     548                 :     {
     549          197311 :         if( EQUAL(poClass->GetProperty( iProperty )->GetSrcElement(),
     550                 :                   pszElement ) )
     551           46565 :             break;
     552                 :     }
     553                 : 
     554           46595 :     if( iProperty == poClass->GetPropertyCount() )
     555                 :     {
     556              30 :         if( poClass->IsSchemaLocked() )
     557                 :         {
     558               0 :             CPLDebug("NAS", "Encountered property missing from class schema.");
     559               0 :             CPLFree(pszValue);
     560               0 :             return;
     561                 :         }
     562                 : 
     563              30 :         CPLString osFieldName;
     564                 : 
     565              30 :         if( strchr(pszElement,'|') == NULL )
     566              19 :             osFieldName = pszElement;
     567                 :         else
     568                 :         {
     569              11 :             osFieldName = strrchr(pszElement,'|') + 1;
     570              11 :             if( poClass->GetPropertyIndex(osFieldName) != -1 )
     571               2 :                 osFieldName = pszElement;
     572                 :         }
     573                 : 
     574                 :         // Does this conflict with an existing property name?
     575              60 :         while( poClass->GetProperty(osFieldName) != NULL )
     576                 :         {
     577               0 :             osFieldName += "_";
     578                 :         }
     579                 : 
     580              30 :         GMLPropertyDefn *poPDefn = new GMLPropertyDefn(osFieldName,pszElement);
     581                 : 
     582              60 :         if( EQUAL(CPLGetConfigOption( "GML_FIELDTYPES", ""), "ALWAYS_STRING") )
     583               0 :             poPDefn->SetType( GMLPT_String );
     584                 : 
     585              30 :         poClass->AddProperty( poPDefn );
     586                 :     }
     587                 : 
     588           46595 :     if ( GMLPropertyDefn::IsSimpleType( poClass->GetProperty( iProperty )->GetType() ) )
     589                 :     {
     590           43277 :         const GMLProperty *poProp = poFeature->GetProperty(iProperty);
     591           43277 :         if ( poProp && poProp->nSubProperties > 0 )
     592                 :         {
     593               0 :             int iId = poClass->GetPropertyIndex( "gml_id" );
     594               0 :             const GMLProperty *poIdProp = poFeature->GetProperty(iId);
     595                 : 
     596                 :             CPLDebug("NAS",
     597                 :                      "Overwriting existing property %s.%s of value '%s' with '%s' (gml_id: %s).",
     598                 :                      poClass->GetName(), pszElement,
     599                 :                      poProp->papszSubProperties[0], pszValue,
     600               0 :                      poIdProp && poIdProp->nSubProperties>0 && poIdProp->papszSubProperties[0] ? poIdProp->papszSubProperties[0] : "(null)" );
     601                 :         }
     602                 :     }
     603                 : 
     604                 : /* -------------------------------------------------------------------- */
     605                 : /*      We want to handle <lage> specially to ensure it is zero         */
     606                 : /*      filled, and treated as a string depspite the numeric            */
     607                 : /*      content. https://trac.wheregroup.com/PostNAS/ticket/9           */
     608                 : /* -------------------------------------------------------------------- */
     609           46595 :     if( strcmp(poClass->GetProperty(iProperty)->GetName(),"lage") == 0 )
     610                 :     {
     611             315 :         if( strlen(pszValue) < 5 )
     612                 :         {
     613               0 :             CPLString osValue = "00000";
     614               0 :             osValue += pszValue;
     615               0 :             poFeature->SetPropertyDirectly( iProperty, CPLStrdup(osValue + osValue.size() - 5) );
     616               0 :             CPLFree(pszValue);
     617                 :         }
     618                 :         else
     619             315 :             poFeature->SetPropertyDirectly( iProperty, pszValue );
     620                 : 
     621             315 :         if( !poClass->IsSchemaLocked() )
     622                 :         {
     623               0 :             poClass->GetProperty(iProperty)->SetWidth( 5 );
     624               0 :             poClass->GetProperty(iProperty)->SetType( GMLPT_String );
     625                 :         }
     626             315 :         return;
     627                 :     }
     628                 : #if 0
     629                 :     else if( strcmp(poClass->GetProperty(iProperty)->GetName(),"signaturnummer") == 0 ||
     630                 :              strcmp(poClass->GetProperty(iProperty)->GetName(),"anlass") == 0 )
     631                 :     {
     632                 :         if( isalpha( pszValue[0] ) && isalpha( pszValue[1] ) && isdigit( pszValue[2] ) )
     633                 :         {
     634                 :             poFeature->SetPropertyDirectly( iProperty, CPLStrdup( pszValue+2 ) );
     635                 : #ifdef DEBUG_VERBOSE
     636                 :             CPLDebug( "NAS", "Skipping two letter prefix of '%s'", pszValue );
     637                 : #endif
     638                 :             CPLFree(pszValue);
     639                 :             return;
     640                 :         }
     641                 :     }
     642                 : #endif
     643           46280 :     else if( strcmp(poClass->GetProperty(iProperty)->GetName(),"kartendarstellung") == 0 ||
     644                 :              strcmp(poClass->GetProperty(iProperty)->GetName(),"rechtsbehelfsverfahren") == 0 )
     645                 :     {
     646                 :         poFeature->SetPropertyDirectly( iProperty,
     647             335 :                                         CPLStrdup( EQUAL( pszValue, "true" ) ? "1" : "0" ) );
     648             335 :         CPLFree(pszValue);
     649                 : 
     650             335 :         if( !poClass->IsSchemaLocked() )
     651                 :         {
     652               2 :             poClass->GetProperty(iProperty)->SetType( GMLPT_Integer );
     653                 :         }
     654             335 :         return;
     655                 :     }
     656                 : 
     657                 : /* -------------------------------------------------------------------- */
     658                 : /*      Set the property                                                */
     659                 : /* -------------------------------------------------------------------- */
     660           45945 :     poFeature->SetPropertyDirectly( iProperty, pszValue );
     661                 : 
     662                 : /* -------------------------------------------------------------------- */
     663                 : /*      Do we need to update the property type?                         */
     664                 : /* -------------------------------------------------------------------- */
     665           45945 :     if( !poClass->IsSchemaLocked() )
     666                 :     {
     667                 :         // Special handling for punktkennung per NAS #12
     668              66 :         if( strcmp(poClass->GetProperty(iProperty)->GetName(),
     669                 :                    "punktkennung") == 0)
     670                 :         {
     671               0 :             poClass->GetProperty(iProperty)->SetWidth( 15 );
     672               0 :             poClass->GetProperty(iProperty)->SetType( GMLPT_String );
     673                 :         }
     674                 :         // Special handling for artDerFlurstuecksgrenze per http://trac.osgeo.org/gdal/ticket/4255
     675              66 :         else if( strcmp(poClass->GetProperty(iProperty)->GetName(),
     676                 :                    "artDerFlurstuecksgrenze") == 0)
     677                 :         {
     678               0 :             poClass->GetProperty(iProperty)->SetType( GMLPT_IntegerList );
     679                 :         }
     680                 :         else
     681                 :             poClass->GetProperty(iProperty)->AnalysePropertyValue(
     682              66 :                 poFeature->GetProperty(iProperty));
     683                 :     }
     684                 : }
     685                 : 
     686                 : /************************************************************************/
     687                 : /*                            LoadClasses()                             */
     688                 : /************************************************************************/
     689                 : 
     690               2 : int NASReader::LoadClasses( const char *pszFile )
     691                 : 
     692                 : {
     693                 :     // Add logic later to determine reasonable default schema file.
     694               2 :     if( pszFile == NULL )
     695               0 :         return FALSE;
     696                 : 
     697                 : /* -------------------------------------------------------------------- */
     698                 : /*      Load the raw XML file.                                          */
     699                 : /* -------------------------------------------------------------------- */
     700                 :     FILE       *fp;
     701                 :     int         nLength;
     702                 :     char        *pszWholeText;
     703                 : 
     704               2 :     fp = VSIFOpen( pszFile, "rb" );
     705                 : 
     706               2 :     if( fp == NULL )
     707                 :     {
     708                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     709               0 :                   "Failed to open file %s.", pszFile );
     710               0 :         return FALSE;
     711                 :     }
     712                 : 
     713               2 :     VSIFSeek( fp, 0, SEEK_END );
     714               2 :     nLength = VSIFTell( fp );
     715               2 :     VSIFSeek( fp, 0, SEEK_SET );
     716                 : 
     717               2 :     pszWholeText = (char *) VSIMalloc(nLength+1);
     718               2 :     if( pszWholeText == NULL )
     719                 :     {
     720                 :         CPLError( CE_Failure, CPLE_AppDefined,
     721                 :                   "Failed to allocate %d byte buffer for %s,\n"
     722                 :                   "is this really a GMLFeatureClassList file?",
     723               0 :                   nLength, pszFile );
     724               0 :         VSIFClose( fp );
     725               0 :         return FALSE;
     726                 :     }
     727                 : 
     728               2 :     if( VSIFRead( pszWholeText, nLength, 1, fp ) != 1 )
     729                 :     {
     730               0 :         VSIFree( pszWholeText );
     731               0 :         VSIFClose( fp );
     732                 :         CPLError( CE_Failure, CPLE_AppDefined,
     733               0 :                   "Read failed on %s.", pszFile );
     734               0 :         return FALSE;
     735                 :     }
     736               2 :     pszWholeText[nLength] = '\0';
     737                 : 
     738               2 :     VSIFClose( fp );
     739                 : 
     740               2 :     if( strstr( pszWholeText, "<GMLFeatureClassList>" ) == NULL )
     741                 :     {
     742               0 :         VSIFree( pszWholeText );
     743                 :         CPLError( CE_Failure, CPLE_AppDefined,
     744                 :                   "File %s does not contain a GMLFeatureClassList tree.",
     745               0 :                   pszFile );
     746               0 :         return FALSE;
     747                 :     }
     748                 : 
     749                 : /* -------------------------------------------------------------------- */
     750                 : /*      Convert to XML parse tree.                                      */
     751                 : /* -------------------------------------------------------------------- */
     752                 :     CPLXMLNode *psRoot;
     753                 : 
     754               2 :     psRoot = CPLParseXMLString( pszWholeText );
     755               2 :     VSIFree( pszWholeText );
     756                 : 
     757                 :     // We assume parser will report errors via CPL.
     758               2 :     if( psRoot == NULL )
     759               0 :         return FALSE;
     760                 : 
     761               2 :     if( psRoot->eType != CXT_Element
     762                 :         || !EQUAL(psRoot->pszValue,"GMLFeatureClassList") )
     763                 :     {
     764               0 :         CPLDestroyXMLNode(psRoot);
     765                 :         CPLError( CE_Failure, CPLE_AppDefined,
     766                 :                   "File %s is not a GMLFeatureClassList document.",
     767               0 :                   pszFile );
     768               0 :         return FALSE;
     769                 :     }
     770                 : 
     771                 : /* -------------------------------------------------------------------- */
     772                 : /*      Extract feature classes for all definitions found.              */
     773                 : /* -------------------------------------------------------------------- */
     774                 :     CPLXMLNode *psThis;
     775                 : 
     776             126 :     for( psThis = psRoot->psChild; psThis != NULL; psThis = psThis->psNext )
     777                 :     {
     778             124 :         if( psThis->eType == CXT_Element
     779                 :             && EQUAL(psThis->pszValue,"GMLFeatureClass") )
     780                 :         {
     781                 :             GMLFeatureClass   *poClass;
     782                 : 
     783             124 :             poClass = new GMLFeatureClass();
     784                 : 
     785             124 :             if( !poClass->InitializeFromXML( psThis ) )
     786                 :             {
     787               0 :                 delete poClass;
     788               0 :                 CPLDestroyXMLNode( psRoot );
     789               0 :                 return FALSE;
     790                 :             }
     791                 : 
     792             124 :             poClass->SetSchemaLocked( TRUE );
     793                 : 
     794             124 :             AddClass( poClass );
     795                 :         }
     796                 :     }
     797                 : 
     798               2 :     CPLDestroyXMLNode( psRoot );
     799                 : 
     800               2 :     SetClassListLocked( TRUE );
     801                 : 
     802               2 :     return TRUE;
     803                 : }
     804                 : 
     805                 : /************************************************************************/
     806                 : /*                            SaveClasses()                             */
     807                 : /************************************************************************/
     808                 : 
     809               2 : int NASReader::SaveClasses( const char *pszFile )
     810                 : 
     811                 : {
     812                 :     // Add logic later to determine reasonable default schema file.
     813               2 :     if( pszFile == NULL )
     814               0 :         return FALSE;
     815                 : 
     816                 : /* -------------------------------------------------------------------- */
     817                 : /*      Create in memory schema tree.                                   */
     818                 : /* -------------------------------------------------------------------- */
     819                 :     CPLXMLNode *psRoot;
     820                 : 
     821               2 :     psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClassList" );
     822                 : 
     823               5 :     for( int iClass = 0; iClass < GetClassCount(); iClass++ )
     824                 :     {
     825               3 :         GMLFeatureClass *poClass = GetClass( iClass );
     826                 : 
     827               3 :         CPLAddXMLChild( psRoot, poClass->SerializeToXML() );
     828                 :     }
     829                 : 
     830                 : /* -------------------------------------------------------------------- */
     831                 : /*      Serialize to disk.                                              */
     832                 : /* -------------------------------------------------------------------- */
     833                 :     FILE        *fp;
     834               2 :     int         bSuccess = TRUE;
     835               2 :     char        *pszWholeText = CPLSerializeXMLTree( psRoot );
     836                 : 
     837               2 :     CPLDestroyXMLNode( psRoot );
     838                 :  
     839               2 :     fp = VSIFOpen( pszFile, "wb" );
     840                 : 
     841               2 :     if( fp == NULL )
     842               0 :         bSuccess = FALSE;
     843               2 :     else if( VSIFWrite( pszWholeText, strlen(pszWholeText), 1, fp ) != 1 )
     844               0 :         bSuccess = FALSE;
     845                 :     else
     846               2 :         VSIFClose( fp );
     847                 : 
     848               2 :     CPLFree( pszWholeText );
     849                 : 
     850               2 :     return bSuccess;
     851                 : }
     852                 : 
     853                 : /************************************************************************/
     854                 : /*                          PrescanForSchema()                          */
     855                 : /*                                                                      */
     856                 : /*      For now we use a pretty dumb approach of just doing a normal    */
     857                 : /*      scan of the whole file, building up the schema information.     */
     858                 : /*      Eventually we hope to do a more efficient scan when just        */
     859                 : /*      looking for schema information.                                 */
     860                 : /************************************************************************/
     861                 : 
     862               3 : int NASReader::PrescanForSchema( int bGetExtents )
     863                 : 
     864                 : {
     865                 :     GMLFeature  *poFeature;
     866                 : 
     867               3 :     if( m_pszFilename == NULL )
     868               0 :         return FALSE;
     869                 : 
     870               3 :     SetClassListLocked( FALSE );
     871                 : 
     872               3 :     ClearClasses();
     873               3 :     if( !SetupParser() )
     874               0 :         return FALSE;
     875                 : 
     876               3 :     std::string osWork;
     877                 : 
     878              11 :     while( (poFeature = NextFeature()) != NULL )
     879                 :     {
     880               5 :         GMLFeatureClass *poClass = poFeature->GetClass();
     881                 : 
     882               5 :         if( poClass->GetFeatureCount() == -1 )
     883               3 :             poClass->SetFeatureCount( 1 );
     884                 :         else
     885               2 :             poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
     886                 : 
     887                 : #ifdef SUPPORT_GEOMETRY
     888               5 :         if( bGetExtents )
     889                 :         {
     890               5 :             OGRGeometry *poGeometry = NULL;
     891                 : 
     892               5 :             const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList();
     893               5 :             if( papsGeometry[0] != NULL )
     894                 :             {
     895               1 :                 poGeometry = (OGRGeometry*) OGR_G_CreateFromGMLTree(papsGeometry[0]);
     896                 :             }
     897                 : 
     898               5 :             if( poGeometry != NULL )
     899                 :             {
     900                 :                 double  dfXMin, dfXMax, dfYMin, dfYMax;
     901               1 :                 OGREnvelope sEnvelope;
     902                 :                 OGRwkbGeometryType eGType = (OGRwkbGeometryType)
     903               1 :                     poClass->GetGeometryType();
     904                 : 
     905                 :                 // Merge SRSName into layer.
     906               1 :                 const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork, FALSE);
     907                 : //                if (pszSRSName != NULL)
     908                 : //                    m_bCanUseGlobalSRSName = FALSE;
     909               1 :                 poClass->MergeSRSName(pszSRSName);
     910                 : 
     911                 :                 // Merge geometry type into layer.
     912               1 :                 if( poClass->GetFeatureCount() == 1 && eGType == wkbUnknown )
     913               1 :                     eGType = wkbNone;
     914                 : 
     915                 :                 poClass->SetGeometryType(
     916                 :                     (int) OGRMergeGeometryTypes(
     917               1 :                         eGType, poGeometry->getGeometryType() ) );
     918                 : 
     919                 :                 // merge extents.
     920               1 :                 poGeometry->getEnvelope( &sEnvelope );
     921               1 :                 delete poGeometry;
     922               1 :                 if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
     923                 :                 {
     924               0 :                     dfXMin = MIN(dfXMin,sEnvelope.MinX);
     925               0 :                     dfXMax = MAX(dfXMax,sEnvelope.MaxX);
     926               0 :                     dfYMin = MIN(dfYMin,sEnvelope.MinY);
     927               0 :                     dfYMax = MAX(dfYMax,sEnvelope.MaxY);
     928                 :                 }
     929                 :                 else
     930                 :                 {
     931               1 :                     dfXMin = sEnvelope.MinX;
     932               1 :                     dfXMax = sEnvelope.MaxX;
     933               1 :                     dfYMin = sEnvelope.MinY;
     934               1 :                     dfYMax = sEnvelope.MaxY;
     935                 :                 }
     936                 : 
     937               1 :                 poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax );
     938                 :             }
     939                 :             else
     940                 :             {
     941               4 :                 if( poClass->GetGeometryType() == (int) wkbUnknown
     942                 :                     && poClass->GetFeatureCount() == 1 )
     943               2 :                     poClass->SetGeometryType( wkbNone );
     944                 :             }
     945                 : #endif /* def SUPPORT_GEOMETRY */
     946                 :         }
     947                 : 
     948               5 :         delete poFeature;
     949                 :     }
     950                 : 
     951               3 :     CleanupParser();
     952                 : 
     953               3 :     return GetClassCount() > 0;
     954                 : }
     955                 : 
     956                 : /************************************************************************/
     957                 : /*                            ResetReading()                            */
     958                 : /************************************************************************/
     959                 : 
     960               9 : void NASReader::ResetReading()
     961                 : 
     962                 : {
     963               9 :     CleanupParser();
     964               9 :     SetFilteredClassName(NULL);
     965               9 : }
     966                 : 
     967                 : /************************************************************************/
     968                 : /*                            CheckForFID()                             */
     969                 : /*                                                                      */
     970                 : /*      Merge the fid attribute into the current field text.            */
     971                 : /************************************************************************/
     972                 : 
     973               6 : void NASReader::CheckForFID( const Attributes &attrs,
     974                 :                              char **ppszCurField )
     975                 : 
     976                 : {
     977                 :     int nIndex;
     978                 :     XMLCh  Name[100];
     979                 : 
     980               6 :     tr_strcpy( Name, "fid" );
     981               6 :     nIndex = attrs.getIndex( Name );
     982                 : 
     983               6 :     if( nIndex != -1 )
     984                 :     {
     985               6 :         char *pszFID = tr_strdup( attrs.getValue( nIndex ) );
     986               6 :         CPLString osCurField = *ppszCurField;
     987                 : 
     988               6 :         osCurField += pszFID;
     989               6 :         CPLFree( pszFID );
     990                 : 
     991               6 :         CPLFree( *ppszCurField );
     992               6 :         *ppszCurField = CPLStrdup(osCurField);
     993                 :     }
     994               6 : }
     995                 : 
     996                 : /************************************************************************/
     997                 : /*                         CheckForRelations()                          */
     998                 : /************************************************************************/
     999                 : 
    1000           37877 : void NASReader::CheckForRelations( const char *pszElement,
    1001                 :                                    const Attributes &attrs )
    1002                 : 
    1003                 : {
    1004           37877 :     GMLFeature *poFeature = GetState()->m_poFeature;
    1005                 : 
    1006           37877 :     CPLAssert( poFeature  != NULL );
    1007                 : 
    1008                 :     int nIndex;
    1009                 :     XMLCh  Name[100];
    1010                 : 
    1011           37877 :     tr_strcpy( Name, "xlink:href" );
    1012           37877 :     nIndex = attrs.getIndex( Name );
    1013                 : 
    1014           37877 :     if( nIndex != -1 )
    1015                 :     {
    1016            2508 :         char *pszHRef = tr_strdup( attrs.getValue( nIndex ) );
    1017                 : 
    1018            2508 :         if( EQUALN(pszHRef,"urn:adv:oid:", 12 ) )
    1019            2508 :             poFeature->AddOBProperty( pszElement, pszHRef );
    1020                 : 
    1021            2508 :         CPLFree( pszHRef );
    1022                 :     }
    1023           37877 : }
    1024                 : 
    1025                 : /************************************************************************/
    1026                 : /*                         HugeFileResolver()                           */
    1027                 : /*      Returns TRUE for success                                        */
    1028                 : /************************************************************************/
    1029                 : 
    1030               0 : int NASReader::HugeFileResolver( const char *pszFile,
    1031                 :                               int bSqliteIsTempFile,
    1032                 :                               int iSqliteCacheMB )
    1033                 : 
    1034                 : {
    1035               0 :     CPLDebug( "NAS", "HugeFileResolver() not currently implemented for NAS." );
    1036               0 :     return FALSE;
    1037                 : }
    1038                 : 
    1039                 : /************************************************************************/
    1040                 : /*                         PrescanForTemplate()                         */
    1041                 : /*      Returns TRUE for success                                        */
    1042                 : /************************************************************************/
    1043                 : 
    1044               0 : int NASReader::PrescanForTemplate( void )
    1045                 : 
    1046                 : {
    1047               0 :     CPLDebug( "NAS", "PrescanForTemplate() not currently implemented for NAS." );
    1048               0 :     return FALSE;
    1049                 : }
    1050                 : 
    1051                 : /************************************************************************/
    1052                 : /*                           ResolveXlinks()                            */
    1053                 : /*      Returns TRUE for success                                        */
    1054                 : /************************************************************************/
    1055                 : 
    1056               0 : int NASReader::ResolveXlinks( const char *pszFile,
    1057                 :                               int* pbOutIsTempFile,
    1058                 :                               char **papszSkip,
    1059                 :                               const int bStrict )
    1060                 : 
    1061                 : {
    1062               0 :     CPLDebug( "NAS", "ResolveXlinks() not currently implemented for NAS." );
    1063               0 :     return FALSE;
    1064                 : }
    1065                 : 
    1066                 : /************************************************************************/
    1067                 : /*                       SetFilteredClassName()                         */
    1068                 : /************************************************************************/
    1069                 : 
    1070              17 : int NASReader::SetFilteredClassName(const char* pszClassName)
    1071                 : {
    1072              17 :     CPLFree(m_pszFilteredClassName);
    1073              17 :     m_pszFilteredClassName = (pszClassName) ? CPLStrdup(pszClassName) : NULL;
    1074              17 :     return TRUE;
    1075                 : }

Generated by: LCOV version 1.7