LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - ogrgmldatasource.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 318
Code covered: 74.5 % Executed lines: 237

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgmldatasource.cpp 20033 2010-07-11 19:06:17Z rouault $
       3                 :  *
       4                 :  * Project:  OGR
       5                 :  * Purpose:  Implements OGRGMLDataSource class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
      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
      22                 :  * OR 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 "ogr_gml.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : 
      34                 : CPL_CVSID("$Id: ogrgmldatasource.cpp 20033 2010-07-11 19:06:17Z rouault $");
      35                 : 
      36                 : /************************************************************************/
      37                 : /*                         OGRGMLDataSource()                         */
      38                 : /************************************************************************/
      39                 : 
      40             119 : OGRGMLDataSource::OGRGMLDataSource()
      41                 : 
      42                 : {
      43             119 :     pszName = NULL;
      44             119 :     papoLayers = NULL;
      45             119 :     nLayers = 0;
      46                 : 
      47             119 :     poReader = NULL;
      48             119 :     fpOutput = NULL;
      49             119 :     bFpOutputIsStdout = FALSE;
      50                 : 
      51             119 :     papszCreateOptions = NULL;
      52             119 :     bOutIsTempFile = FALSE;
      53             119 : }
      54                 : 
      55                 : /************************************************************************/
      56                 : /*                        ~OGRGMLDataSource()                         */
      57                 : /************************************************************************/
      58                 : 
      59             119 : OGRGMLDataSource::~OGRGMLDataSource()
      60                 : 
      61                 : {
      62                 : 
      63             119 :     if( fpOutput != NULL )
      64                 :     {
      65                 :         PrintLine( fpOutput, "%s", 
      66               2 :                     "</ogr:FeatureCollection>" );
      67                 : 
      68               2 :         InsertHeader();
      69                 : 
      70               2 :         if( nBoundedByLocation != -1 
      71                 :             && sBoundingRect.IsInit() 
      72                 :             && VSIFSeekL( fpOutput, nBoundedByLocation, SEEK_SET ) == 0 )
      73                 :         {
      74               0 :             PrintLine( fpOutput, "  <gml:boundedBy>" );
      75               0 :             PrintLine( fpOutput, "    <gml:Box>" );
      76                 :             PrintLine( fpOutput, 
      77                 :                         "      <gml:coord><gml:X>%.16g</gml:X>"
      78                 :                         "<gml:Y>%.16g</gml:Y></gml:coord>",
      79               0 :                         sBoundingRect.MinX, sBoundingRect.MinY );
      80                 :             PrintLine( fpOutput, 
      81                 :                         "      <gml:coord><gml:X>%.16g</gml:X>"
      82                 :                         "<gml:Y>%.16g</gml:Y></gml:coord>",
      83               0 :                         sBoundingRect.MaxX, sBoundingRect.MaxY );
      84               0 :             PrintLine( fpOutput, "    </gml:Box>" );
      85               0 :             PrintLine( fpOutput, "  </gml:boundedBy>" );
      86                 :         }
      87                 : 
      88               2 :         VSIFCloseL( fpOutput );
      89                 :     }
      90                 : 
      91             119 :     CSLDestroy( papszCreateOptions );
      92             119 :     CPLFree( pszName );
      93                 : 
      94             138 :     for( int i = 0; i < nLayers; i++ )
      95              19 :         delete papoLayers[i];
      96                 :     
      97             119 :     CPLFree( papoLayers );
      98                 : 
      99             119 :     if( poReader )
     100                 :     {
     101              20 :         if (bOutIsTempFile)
     102               1 :             VSIUnlink(poReader->GetSourceFileName());
     103              20 :         delete poReader;
     104                 :     }
     105             119 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                                Open()                                */
     109                 : /************************************************************************/
     110                 : 
     111             117 : int OGRGMLDataSource::Open( const char * pszNewName, int bTestOpen )
     112                 : 
     113                 : {
     114                 :     FILE        *fp;
     115                 :     char        szHeader[1000];
     116                 : 
     117                 : /* -------------------------------------------------------------------- */
     118                 : /*      Open the source file.                                           */
     119                 : /* -------------------------------------------------------------------- */
     120             117 :     fp = VSIFOpenL( pszNewName, "r" );
     121             117 :     if( fp == NULL )
     122                 :     {
     123               7 :         if( !bTestOpen )
     124                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     125                 :                       "Failed to open GML file `%s'.", 
     126               0 :                       pszNewName );
     127                 : 
     128               7 :         return FALSE;
     129                 :     }
     130                 : 
     131                 : /* -------------------------------------------------------------------- */
     132                 : /*      If we aren't sure it is GML, load a header chunk and check      */
     133                 : /*      for signs it is GML                                             */
     134                 : /* -------------------------------------------------------------------- */
     135             110 :     if( bTestOpen )
     136                 :     {
     137             110 :         size_t nRead = VSIFReadL( szHeader, 1, sizeof(szHeader), fp );
     138             110 :         if (nRead <= 0)
     139                 :         {
     140               1 :             VSIFCloseL( fp );
     141               1 :             return FALSE;
     142                 :         }
     143             109 :         szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
     144                 : 
     145                 : /* -------------------------------------------------------------------- */
     146                 : /*      Check for a UTF-8 BOM and skip if found                         */
     147                 : /*                                                                      */
     148                 : /*      TODO: BOM is variable-lenght parameter and depends on encoding. */
     149                 : /*            Add BOM detection for other encodings.                    */
     150                 : /* -------------------------------------------------------------------- */
     151                 : 
     152                 :         // Used to skip to actual beginning of XML data
     153             109 :         char* szPtr = szHeader;
     154                 : 
     155             109 :         if( ( (unsigned char)szHeader[0] == 0xEF )
     156                 :             && ( (unsigned char)szHeader[1] == 0xBB )
     157                 :             && ( (unsigned char)szHeader[2] == 0xBF) )
     158                 :         {
     159               1 :             szPtr += 3;
     160                 :         }
     161                 : 
     162                 : /* -------------------------------------------------------------------- */
     163                 : /*      Here, we expect the opening chevrons of GML tree root element   */
     164                 : /* -------------------------------------------------------------------- */
     165             109 :         if( szPtr[0] != '<' 
     166                 :             || strstr(szPtr,"opengis.net/gml") == NULL )
     167                 :         {
     168              89 :             VSIFCloseL( fp );
     169              89 :             return FALSE;
     170                 :         }
     171                 :     }
     172                 :     
     173                 : /* -------------------------------------------------------------------- */
     174                 : /*      We assume now that it is GML.  Close and instantiate a          */
     175                 : /*      GMLReader on it.                                                */
     176                 : /* -------------------------------------------------------------------- */
     177              20 :     VSIFCloseL( fp );
     178                 :     
     179              20 :     poReader = CreateGMLReader();
     180              20 :     if( poReader == NULL )
     181                 :     {
     182                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     183                 :                   "File %s appears to be GML but the GML reader can't\n"
     184                 :                   "be instantiated, likely because Xerces or Expat support wasn't\n"
     185                 :                   "configured in.", 
     186               0 :                   pszNewName );
     187               0 :         return FALSE;
     188                 :     }
     189                 : 
     190              20 :     poReader->SetSourceFile( pszNewName );
     191                 :     
     192                 : /* -------------------------------------------------------------------- */
     193                 : /*      Resolve the xlinks in the source file and save it with the      */
     194                 : /*      extension ".resolved.gml". The source file will to set to that. */
     195                 : /* -------------------------------------------------------------------- */
     196                 : 
     197              20 :     char *pszXlinkResolvedFilename = NULL;
     198              20 :     const char *pszOption = CPLGetConfigOption("GML_SAVE_RESOLVED_TO", NULL);
     199              20 :     int bResolve = TRUE;
     200              20 :     if( pszOption != NULL )
     201                 :     {
     202               0 :         if( EQUALN( pszOption, "SAME", 4 ) )
     203                 :         {
     204                 :             // "SAME" will overwrite the existing gml file
     205               0 :             pszXlinkResolvedFilename = CPLStrdup( pszNewName );
     206                 :         }
     207               0 :         else if( ( CPLStrnlen( pszOption, 5 ) >= 5 ) &&
     208                 :                  EQUALN( pszOption - 4 + strlen( pszOption ), ".gml", 4 ) )
     209                 :         {
     210                 :             // Any string ending with ".gml" will try and write to it
     211               0 :             pszXlinkResolvedFilename = CPLStrdup( pszNewName );
     212                 :         }
     213                 :     }
     214                 :     else
     215                 :     {
     216                 :         // Default action would be to use a file with the extension
     217                 :         // changed to resolved.gml
     218                 :         pszXlinkResolvedFilename = CPLStrdup(
     219              20 :                             CPLResetExtension( pszNewName, "resolved.gml" ) );
     220                 : 
     221                 :         // Check if the file already exists.
     222                 :         VSIStatBufL sResStatBuf, sGMLStatBuf;
     223              20 :         if( VSIStatL( pszXlinkResolvedFilename, &sResStatBuf ) == 0 )
     224                 :         {
     225               0 :             VSIStatL( pszNewName, &sGMLStatBuf );
     226               0 :             if( sGMLStatBuf.st_mtime > sResStatBuf.st_mtime )
     227                 :             {
     228                 :                 CPLDebug( "GML", 
     229                 :                           "Found %s but ignoring because it appears\n"
     230                 :                           "be older than the associated GML file.", 
     231               0 :                           pszXlinkResolvedFilename );
     232               0 :                 bResolve = FALSE;
     233                 :             }
     234                 :             else
     235                 :             {
     236               0 :                 poReader->SetSourceFile( pszXlinkResolvedFilename );
     237               0 :                 bResolve = FALSE;
     238                 :             }
     239                 :         }
     240                 :     }
     241                 : 
     242                 :     const char *pszSkipOption = CPLGetConfigOption( "GML_SKIP_RESOLVE_ELEMS",
     243              20 :                                                     "");
     244              20 :     char **papszSkip = NULL;
     245              20 :     if( EQUAL( pszSkipOption, "ALL" ) )
     246               0 :         bResolve = FALSE;
     247                 :     else
     248                 :         papszSkip = CSLTokenizeString2( pszSkipOption, ",",
     249                 :                                            CSLT_STRIPLEADSPACES |
     250              20 :                                            CSLT_STRIPENDSPACES );
     251                 : 
     252              20 :     if( bResolve )
     253              20 :         poReader->ResolveXlinks( pszXlinkResolvedFilename, &bOutIsTempFile, papszSkip );
     254                 : 
     255              20 :     CPLFree( pszXlinkResolvedFilename );
     256              20 :     CSLDestroy( papszSkip );
     257                 : 
     258              20 :     pszName = CPLStrdup( pszNewName );
     259                 : 
     260                 : /* -------------------------------------------------------------------- */
     261                 : /*      Can we find a GML Feature Schema (.gfs) for the input file?     */
     262                 : /* -------------------------------------------------------------------- */
     263                 :     const char *pszGFSFilename;
     264                 :     VSIStatBufL sGFSStatBuf, sGMLStatBuf;
     265              20 :     int        bHaveSchema = FALSE;
     266                 : 
     267              20 :     pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
     268              20 :     if( VSIStatL( pszGFSFilename, &sGFSStatBuf ) == 0 )
     269                 :     {
     270               5 :         VSIStatL( pszNewName, &sGMLStatBuf );
     271                 : 
     272               5 :         if( sGMLStatBuf.st_mtime > sGFSStatBuf.st_mtime )
     273                 :         {
     274                 :             CPLDebug( "GML", 
     275                 :                       "Found %s but ignoring because it appears\n"
     276                 :                       "be older than the associated GML file.", 
     277               0 :                       pszGFSFilename );
     278                 :         }
     279                 :         else
     280                 :         {
     281               5 :             bHaveSchema = poReader->LoadClasses( pszGFSFilename );
     282                 :         }
     283                 :     }
     284                 : 
     285                 : /* -------------------------------------------------------------------- */
     286                 : /*      Can we find an xsd which might conform to tbe GML3 Level 0      */
     287                 : /*      profile?  We really ought to look for it based on the rules     */
     288                 : /*      schemaLocation in the GML feature collection but for now we     */
     289                 : /*      just hopes it is in the same director with the same name.       */
     290                 : /* -------------------------------------------------------------------- */
     291                 :     const char *pszXSDFilename;
     292                 : 
     293              20 :     if( !bHaveSchema )
     294                 :     {
     295              15 :         pszXSDFilename = CPLResetExtension( pszNewName, "xsd" );
     296              15 :         if( VSIStatL( pszXSDFilename, &sGMLStatBuf ) == 0 )
     297                 :         {
     298               3 :             bHaveSchema = poReader->ParseXSD( pszXSDFilename );
     299                 :         }
     300                 :     }
     301                 :     
     302                 : /* -------------------------------------------------------------------- */
     303                 : /*      Force a first pass to establish the schema.  Eventually we      */
     304                 : /*      will have mechanisms for remembering the schema and related     */
     305                 : /*      information.                                                    */
     306                 : /* -------------------------------------------------------------------- */
     307              20 :     if( !bHaveSchema && !poReader->PrescanForSchema( TRUE ) )
     308                 :     {
     309                 :         // we assume an errors have been reported.
     310               4 :         return FALSE;
     311                 :     }
     312                 : 
     313                 : /* -------------------------------------------------------------------- */
     314                 : /*      Save the schema file if possible.  Don't make a fuss if we      */
     315                 : /*      can't ... could be read-only directory or something.            */
     316                 : /* -------------------------------------------------------------------- */
     317              16 :     if( !bHaveSchema && !poReader->HasStoppedParsing() &&
     318                 :         !EQUALN(pszNewName, "/vsitar/", strlen("/vsitar/")) &&
     319                 :         !EQUALN(pszNewName, "/vsigzip/", strlen("/vsigzip/")) &&
     320                 :         !EQUALN(pszNewName, "/vsizip/", strlen("/vsizip/")))
     321                 :     {
     322               8 :         FILE    *fp = NULL;
     323                 : 
     324               8 :         pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
     325               8 :         if( VSIStatL( pszGFSFilename, &sGFSStatBuf ) != 0 
     326                 :             && (fp = VSIFOpenL( pszGFSFilename, "wt" )) != NULL )
     327                 :         {
     328               8 :             VSIFCloseL( fp );
     329               8 :             poReader->SaveClasses( pszGFSFilename );
     330                 :         }
     331                 :         else
     332                 :         {
     333                 :             CPLDebug("GML", 
     334                 :                      "Not saving %s files already exists or can't be created.",
     335               0 :                      pszGFSFilename );
     336                 :         }
     337                 :     }
     338                 : 
     339                 : /* -------------------------------------------------------------------- */
     340                 : /*      Translate the GMLFeatureClasses into layers.                    */
     341                 : /* -------------------------------------------------------------------- */
     342                 :     papoLayers = (OGRGMLLayer **)
     343              16 :         CPLCalloc( sizeof(OGRGMLLayer *), poReader->GetClassCount());
     344              16 :     nLayers = 0;
     345                 : 
     346              49 :     while( nLayers < poReader->GetClassCount() )
     347                 :     {
     348              17 :         papoLayers[nLayers] = TranslateGMLSchema(poReader->GetClass(nLayers));
     349              17 :         nLayers++;
     350                 :     }
     351                 :     
     352                 : 
     353                 :     
     354              16 :     return TRUE;
     355                 : }
     356                 : 
     357                 : /************************************************************************/
     358                 : /*                         TranslateGMLSchema()                         */
     359                 : /************************************************************************/
     360                 : 
     361              17 : OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
     362                 : 
     363                 : {
     364                 :     OGRGMLLayer *poLayer;
     365                 :     OGRwkbGeometryType eGType 
     366              17 :         = (OGRwkbGeometryType) poClass->GetGeometryType();
     367                 : 
     368              17 :     if( poClass->GetFeatureCount() == 0 )
     369               0 :         eGType = wkbUnknown;
     370                 :     
     371                 : /* -------------------------------------------------------------------- */
     372                 : /*      Create an empty layer.                                          */
     373                 : /* -------------------------------------------------------------------- */
     374                 :     poLayer = new OGRGMLLayer( poClass->GetName(), NULL, FALSE, 
     375              17 :                                eGType, this );
     376                 : 
     377                 : /* -------------------------------------------------------------------- */
     378                 : /*      Added attributes (properties).                                  */
     379                 : /* -------------------------------------------------------------------- */
     380              74 :     for( int iField = 0; iField < poClass->GetPropertyCount(); iField++ )
     381                 :     {
     382              57 :         GMLPropertyDefn *poProperty = poClass->GetProperty( iField );
     383                 :         OGRFieldType eFType;
     384                 : 
     385              57 :         if( poProperty->GetType() == GMLPT_Untyped )
     386               0 :             eFType = OFTString;
     387              57 :         else if( poProperty->GetType() == GMLPT_String )
     388              24 :             eFType = OFTString;
     389              33 :         else if( poProperty->GetType() == GMLPT_Integer )
     390              25 :             eFType = OFTInteger;
     391               8 :         else if( poProperty->GetType() == GMLPT_Real )
     392               8 :             eFType = OFTReal;
     393               0 :         else if( poProperty->GetType() == GMLPT_StringList )
     394               0 :             eFType = OFTStringList;
     395               0 :         else if( poProperty->GetType() == GMLPT_IntegerList )
     396               0 :             eFType = OFTIntegerList;
     397               0 :         else if( poProperty->GetType() == GMLPT_RealList )
     398               0 :             eFType = OFTRealList;
     399                 :         else
     400               0 :             eFType = OFTString;
     401                 :         
     402              57 :         OGRFieldDefn oField( poProperty->GetName(), eFType );
     403              57 :         if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
     404               0 :           oField.SetName(poProperty->GetName()+4);
     405              57 :         if( poProperty->GetWidth() > 0 )
     406              22 :             oField.SetWidth( poProperty->GetWidth() );
     407              57 :         if( poProperty->GetPrecision() > 0 )
     408               2 :             oField.SetPrecision( poProperty->GetPrecision() );
     409                 : 
     410              57 :         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     411                 :     }
     412                 : 
     413              17 :     return poLayer;
     414                 : }
     415                 : 
     416                 : /************************************************************************/
     417                 : /*                               Create()                               */
     418                 : /************************************************************************/
     419                 : 
     420                 : int OGRGMLDataSource::Create( const char *pszFilename, 
     421               2 :                               char **papszOptions )
     422                 : 
     423                 : {
     424               2 :     if( fpOutput != NULL || poReader != NULL )
     425                 :     {
     426               0 :         CPLAssert( FALSE );
     427               0 :         return FALSE;
     428                 :     }
     429                 : 
     430                 : /* -------------------------------------------------------------------- */
     431                 : /*      Create the output file.                                         */
     432                 : /* -------------------------------------------------------------------- */
     433               2 :     pszName = CPLStrdup( pszFilename );
     434                 : 
     435               2 :     if( EQUAL(pszFilename,"stdout") || EQUAL(pszFilename,"/vsistdout/"))
     436                 :     {
     437               0 :         fpOutput = VSIFOpenL("/vsistdout/", "wb");
     438               0 :         bFpOutputIsStdout = TRUE;
     439                 :     }
     440                 :     else
     441               2 :         fpOutput = VSIFOpenL( pszFilename, "wb+" );
     442               2 :     if( fpOutput == NULL )
     443                 :     {
     444                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     445                 :                   "Failed to create GML file %s.", 
     446               0 :                   pszFilename );
     447               0 :         return FALSE;
     448                 :     }
     449                 : 
     450                 : /* -------------------------------------------------------------------- */
     451                 : /*      Write out "standard" header.                                    */
     452                 : /* -------------------------------------------------------------------- */
     453                 :     PrintLine( fpOutput, "%s", 
     454               2 :                 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" );
     455                 : 
     456               2 :     nSchemaInsertLocation = VSIFTellL( fpOutput );
     457                 : 
     458                 :     PrintLine( fpOutput, "%s", 
     459               2 :                 "<ogr:FeatureCollection" );
     460                 : 
     461                 : /* -------------------------------------------------------------------- */
     462                 : /*      Write out schema info if provided in creation options.          */
     463                 : /* -------------------------------------------------------------------- */
     464               2 :     const char *pszSchemaURI = CSLFetchNameValue(papszOptions,"XSISCHEMAURI");
     465               2 :     const char *pszSchemaOpt = CSLFetchNameValue( papszOptions, "XSISCHEMA" );
     466                 : 
     467               2 :     if( pszSchemaURI != NULL )
     468                 :     {
     469                 :         PrintLine( fpOutput, 
     470               0 :               "     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
     471                 :         PrintLine( fpOutput, 
     472                 :               "     xsi:schemaLocation=\"%s\"", 
     473               0 :                     CSLFetchNameValue( papszOptions, "XSISCHEMAURI" ) );
     474                 :     }
     475               2 :     else if( pszSchemaOpt == NULL || EQUAL(pszSchemaOpt,"EXTERNAL") )
     476                 :     {
     477               2 :         char *pszBasename = CPLStrdup(CPLGetBasename( pszName ));
     478                 : 
     479                 :         PrintLine( fpOutput, 
     480               2 :               "     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
     481                 :         PrintLine( fpOutput, 
     482                 :               "     xsi:schemaLocation=\"http://ogr.maptools.org/ %s\"", 
     483               2 :                     CPLResetExtension( pszBasename, "xsd" ) );
     484               2 :         CPLFree( pszBasename );
     485                 :     }
     486                 : 
     487                 :     PrintLine( fpOutput, "%s", 
     488               2 :                 "     xmlns:ogr=\"http://ogr.maptools.org/\"" );
     489                 :     PrintLine( fpOutput, "%s", 
     490               2 :                 "     xmlns:gml=\"http://www.opengis.net/gml\">" );
     491                 : 
     492                 : /* -------------------------------------------------------------------- */
     493                 : /*      Should we initialize an area to place the boundedBy element?    */
     494                 : /*      We will need to seek back to fill it in.                        */
     495                 : /* -------------------------------------------------------------------- */
     496               2 :     if( CSLFetchBoolean( papszOptions, "BOUNDEDBY", TRUE ) )
     497                 :     {
     498               2 :         nBoundedByLocation = VSIFTellL( fpOutput );
     499                 : 
     500               2 :         if( nBoundedByLocation != -1 )
     501               2 :             PrintLine( fpOutput, "%280s", "" );
     502                 :     }
     503                 :     else
     504               0 :         nBoundedByLocation = -1;
     505                 : 
     506               2 :     return TRUE;
     507                 : }
     508                 : 
     509                 : /************************************************************************/
     510                 : /*                            CreateLayer()                             */
     511                 : /************************************************************************/
     512                 : 
     513                 : OGRLayer *
     514                 : OGRGMLDataSource::CreateLayer( const char * pszLayerName,
     515                 :                                OGRSpatialReference *poSRS,
     516                 :                                OGRwkbGeometryType eType,
     517               2 :                                char ** papszOptions )
     518                 : 
     519                 : {
     520                 : /* -------------------------------------------------------------------- */
     521                 : /*      Verify we are in update mode.                                   */
     522                 : /* -------------------------------------------------------------------- */
     523               2 :     if( fpOutput == NULL )
     524                 :     {
     525                 :         CPLError( CE_Failure, CPLE_NoWriteAccess,
     526                 :                   "Data source %s opened for read access.\n"
     527                 :                   "New layer %s cannot be created.\n",
     528               0 :                   pszName, pszLayerName );
     529                 : 
     530               0 :         return NULL;
     531                 :     }
     532                 : 
     533                 : /* -------------------------------------------------------------------- */
     534                 : /*      Ensure name is safe as an element name.                         */
     535                 : /* -------------------------------------------------------------------- */
     536               2 :     char *pszCleanLayerName = CPLStrdup( pszLayerName );
     537                 : 
     538               2 :     CPLCleanXMLElementName( pszCleanLayerName );
     539               2 :     if( strcmp(pszCleanLayerName,pszLayerName) != 0 )
     540                 :     {
     541                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     542                 :                   "Layer name '%s' adjusted to '%s' for XML validity.",
     543               0 :                   pszLayerName, pszCleanLayerName );
     544                 :     }
     545                 : 
     546                 : /* -------------------------------------------------------------------- */
     547                 : /*      Create the layer object.                                        */
     548                 : /* -------------------------------------------------------------------- */
     549                 :     OGRGMLLayer *poLayer;
     550                 : 
     551               2 :     poLayer = new OGRGMLLayer( pszCleanLayerName, poSRS, TRUE, eType, this );
     552                 : 
     553               2 :     CPLFree( pszCleanLayerName );
     554                 : 
     555                 : /* -------------------------------------------------------------------- */
     556                 : /*      Add layer to data source layer list.                            */
     557                 : /* -------------------------------------------------------------------- */
     558                 :     papoLayers = (OGRGMLLayer **)
     559               2 :         CPLRealloc( papoLayers,  sizeof(OGRGMLLayer *) * (nLayers+1) );
     560                 :     
     561               2 :     papoLayers[nLayers++] = poLayer;
     562                 : 
     563               2 :     return poLayer;
     564                 : }
     565                 : 
     566                 : /************************************************************************/
     567                 : /*                           TestCapability()                           */
     568                 : /************************************************************************/
     569                 : 
     570               0 : int OGRGMLDataSource::TestCapability( const char * pszCap )
     571                 : 
     572                 : {
     573               0 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     574               0 :         return TRUE;
     575                 :     else
     576               0 :         return FALSE;
     577                 : }
     578                 : 
     579                 : /************************************************************************/
     580                 : /*                              GetLayer()                              */
     581                 : /************************************************************************/
     582                 : 
     583              17 : OGRLayer *OGRGMLDataSource::GetLayer( int iLayer )
     584                 : 
     585                 : {
     586              17 :     if( iLayer < 0 || iLayer >= nLayers )
     587               0 :         return NULL;
     588                 :     else
     589              17 :         return papoLayers[iLayer];
     590                 : }
     591                 : 
     592                 : /************************************************************************/
     593                 : /*                            GrowExtents()                             */
     594                 : /************************************************************************/
     595                 : 
     596               0 : void OGRGMLDataSource::GrowExtents( OGREnvelope *psGeomBounds )
     597                 : 
     598                 : {
     599               0 :     sBoundingRect.Merge( *psGeomBounds );
     600               0 : }
     601                 : 
     602                 : /************************************************************************/
     603                 : /*                            InsertHeader()                            */
     604                 : /*                                                                      */
     605                 : /*      This method is used to update boundedby info for a              */
     606                 : /*      dataset, and insert schema descriptions depending on            */
     607                 : /*      selection options in effect.                                    */
     608                 : /************************************************************************/
     609                 : 
     610               2 : void OGRGMLDataSource::InsertHeader()
     611                 : 
     612                 : {
     613                 :     FILE        *fpSchema;
     614               2 :     int         nSchemaStart = 0;
     615                 : 
     616               2 :     if( fpOutput == NULL || bFpOutputIsStdout )
     617               0 :         return;
     618                 : 
     619                 : /* -------------------------------------------------------------------- */
     620                 : /*      Do we want to write the schema within the GML instance doc      */
     621                 : /*      or to a separate file?  For now we only support external.       */
     622                 : /* -------------------------------------------------------------------- */
     623                 :     const char *pszSchemaURI = CSLFetchNameValue(papszCreateOptions,
     624               2 :                                                  "XSISCHEMAURI");
     625                 :     const char *pszSchemaOpt = CSLFetchNameValue( papszCreateOptions, 
     626               2 :                                                   "XSISCHEMA" );
     627                 : 
     628               2 :     if( pszSchemaURI != NULL )
     629               0 :         return;
     630                 : 
     631               4 :     if( pszSchemaOpt == NULL || EQUAL(pszSchemaOpt,"EXTERNAL") )
     632                 :     {
     633               2 :         const char *pszXSDFilename = CPLResetExtension( pszName, "xsd" );
     634                 : 
     635               2 :         fpSchema = VSIFOpenL( pszXSDFilename, "wt" );
     636               2 :         if( fpSchema == NULL )
     637                 :         {
     638                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     639                 :                       "Failed to open file %.500s for schema output.", 
     640               0 :                       pszXSDFilename );
     641               0 :             return;
     642                 :         }
     643               2 :         PrintLine( fpSchema, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
     644                 :     }
     645               0 :     else if( EQUAL(pszSchemaOpt,"INTERNAL") )
     646                 :     {
     647               0 :         nSchemaStart = VSIFTellL( fpOutput );
     648               0 :         fpSchema = fpOutput;
     649                 :     }
     650                 :     else                                                               
     651               0 :         return;
     652                 : 
     653                 : /* ==================================================================== */
     654                 : /*      Write the schema section at the end of the file.  Once          */
     655                 : /*      complete, we will read it back in, and then move the whole      */
     656                 : /*      file "down" enough to insert the schema at the beginning.       */
     657                 : /* ==================================================================== */
     658                 : 
     659                 : /* -------------------------------------------------------------------- */
     660                 : /*      Emit the start of the schema section.                           */
     661                 : /* -------------------------------------------------------------------- */
     662               2 :     const char *pszTargetNameSpace = "http://ogr.maptools.org/";
     663               2 :     const char *pszPrefix = "ogr";
     664                 : 
     665                 :     PrintLine( fpSchema, 
     666                 :                 "<xs:schema targetNamespace=\"%s\" xmlns:%s=\"%s\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:gml=\"http://www.opengis.net/gml\" elementFormDefault=\"qualified\" version=\"1.0\">", 
     667               2 :                 pszTargetNameSpace, pszPrefix, pszTargetNameSpace );
     668                 :     
     669                 :     PrintLine( fpSchema, 
     670               2 :                 "<xs:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://schemas.opengeospatial.net/gml/2.1.2/feature.xsd\"/>" );
     671                 : 
     672                 : /* -------------------------------------------------------------------- */
     673                 : /*      Define the FeatureCollection                                    */
     674                 : /* -------------------------------------------------------------------- */
     675                 :     PrintLine( fpSchema, 
     676                 :                 "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_FeatureCollection\"/>", 
     677               2 :                 pszPrefix );
     678                 : 
     679               2 :     PrintLine( fpSchema, "<xs:complexType name=\"FeatureCollectionType\">");
     680               2 :     PrintLine( fpSchema, "  <xs:complexContent>" );
     681               2 :     PrintLine( fpSchema, "    <xs:extension base=\"gml:AbstractFeatureCollectionType\">" );
     682               2 :     PrintLine( fpSchema, "      <xs:attribute name=\"lockId\" type=\"xs:string\" use=\"optional\"/>" );
     683               2 :     PrintLine( fpSchema, "      <xs:attribute name=\"scope\" type=\"xs:string\" use=\"optional\"/>" );
     684               2 :     PrintLine( fpSchema, "    </xs:extension>" );
     685               2 :     PrintLine( fpSchema, "  </xs:complexContent>" );
     686               2 :     PrintLine( fpSchema, "</xs:complexType>" );
     687                 : 
     688                 : /* ==================================================================== */
     689                 : /*      Define the schema for each layer.                               */
     690                 : /* ==================================================================== */
     691                 :     int iLayer;
     692                 : 
     693               4 :     for( iLayer = 0; iLayer < GetLayerCount(); iLayer++ )
     694                 :     {
     695               2 :         OGRFeatureDefn *poFDefn = GetLayer(iLayer)->GetLayerDefn();
     696                 :         
     697                 : /* -------------------------------------------------------------------- */
     698                 : /*      Emit initial stuff for a feature type.                          */
     699                 : /* -------------------------------------------------------------------- */
     700                 :         PrintLine(
     701                 :             fpSchema,
     702                 :             "<xs:element name=\"%s\" type=\"%s:%s_Type\" substitutionGroup=\"gml:_Feature\"/>",
     703               2 :             poFDefn->GetName(), pszPrefix, poFDefn->GetName() );
     704                 : 
     705               2 :         PrintLine( fpSchema, "<xs:complexType name=\"%s_Type\">", poFDefn->GetName());
     706               2 :         PrintLine( fpSchema, "  <xs:complexContent>");
     707               2 :         PrintLine( fpSchema, "    <xs:extension base=\"gml:AbstractFeatureType\">");
     708               2 :         PrintLine( fpSchema, "      <xs:sequence>");
     709                 : 
     710                 : /* -------------------------------------------------------------------- */
     711                 : /*      Define the geometry attribute.  For now I always use the        */
     712                 : /*      generic geometry type, but eventually we should express         */
     713                 : /*      particulars if available.                                       */
     714                 : /* -------------------------------------------------------------------- */
     715                 :         PrintLine( fpSchema,
     716               2 :             "        <xs:element name=\"geometryProperty\" type=\"gml:GeometryPropertyType\" nillable=\"true\" minOccurs=\"1\" maxOccurs=\"1\"/>" );
     717                 :             
     718                 : /* -------------------------------------------------------------------- */
     719                 : /*      Emit each of the attributes.                                    */
     720                 : /* -------------------------------------------------------------------- */
     721               8 :         for( int iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
     722                 :         {
     723               6 :             OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(iField);
     724                 : 
     725               6 :             if( poFieldDefn->GetType() == OFTInteger )
     726                 :             {
     727                 :                 int nWidth;
     728                 : 
     729               1 :                 if( poFieldDefn->GetWidth() > 0 )
     730               1 :                     nWidth = poFieldDefn->GetWidth();
     731                 :                 else
     732               0 :                     nWidth = 16;
     733                 : 
     734               1 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">", poFieldDefn->GetNameRef());
     735               1 :                 PrintLine( fpSchema, "          <xs:simpleType>");
     736               1 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:integer\">");
     737               1 :                 PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
     738               1 :                 PrintLine( fpSchema, "            </xs:restriction>");
     739               1 :                 PrintLine( fpSchema, "          </xs:simpleType>");
     740               1 :                 PrintLine( fpSchema, "        </xs:element>");
     741                 :             }
     742               5 :             else if( poFieldDefn->GetType() == OFTReal )
     743                 :             {
     744                 :                 int nWidth, nDecimals;
     745                 : 
     746               2 :                 if( poFieldDefn->GetPrecision() == 0 )
     747               1 :                     nDecimals = 0;
     748                 :                 else
     749               1 :                     nDecimals = poFieldDefn->GetPrecision();
     750                 : 
     751               2 :                 if( poFieldDefn->GetWidth() > 0 )
     752               1 :                     nWidth = poFieldDefn->GetWidth();
     753                 :                 else
     754               1 :                     nWidth = 33;
     755                 : 
     756               2 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
     757               2 :                 PrintLine( fpSchema, "          <xs:simpleType>");
     758               2 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:decimal\">");
     759               2 :                 PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
     760               2 :                 PrintLine( fpSchema, "              <xs:fractionDigits value=\"%d\"/>", nDecimals);
     761               2 :                 PrintLine( fpSchema, "            </xs:restriction>");
     762               2 :                 PrintLine( fpSchema, "          </xs:simpleType>");
     763               2 :                 PrintLine( fpSchema, "        </xs:element>");
     764                 :             }
     765               3 :             else if( poFieldDefn->GetType() == OFTString )
     766                 :             {
     767                 :                 char szMaxLength[48];
     768                 : 
     769               2 :                 if( poFieldDefn->GetWidth() == 0 )
     770               1 :                     sprintf( szMaxLength, "unbounded" );
     771                 :                 else
     772               1 :                     sprintf( szMaxLength, "%d", poFieldDefn->GetWidth() );
     773                 : 
     774               2 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
     775               2 :                 PrintLine( fpSchema, "          <xs:simpleType>");
     776               2 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:string\">");
     777               2 :                 PrintLine( fpSchema, "              <xs:maxLength value=\"%s\"/>", szMaxLength);
     778               2 :                 PrintLine( fpSchema, "            </xs:restriction>");
     779               2 :                 PrintLine( fpSchema, "          </xs:simpleType>");
     780               2 :                 PrintLine( fpSchema, "        </xs:element>");
     781                 :             }
     782               1 :             else if( poFieldDefn->GetType() == OFTDate || poFieldDefn->GetType() == OFTDateTime )
     783                 :             {
     784               1 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
     785               1 :                 PrintLine( fpSchema, "          <xs:simpleType>");
     786               1 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:string\">");
     787               1 :                 PrintLine( fpSchema, "              <xs:maxLength value=\"unbounded\"/>");
     788               1 :                 PrintLine( fpSchema, "            </xs:restriction>");
     789               1 :                 PrintLine( fpSchema, "          </xs:simpleType>");
     790               1 :                 PrintLine( fpSchema, "        </xs:element>");
     791                 :             }
     792                 :             else
     793                 :             {
     794                 :                 /* TODO */
     795                 :             }
     796                 :         } /* next field */
     797                 : 
     798                 : /* -------------------------------------------------------------------- */
     799                 : /*      Finish off feature type.                                        */
     800                 : /* -------------------------------------------------------------------- */
     801               2 :         PrintLine( fpSchema, "      </xs:sequence>");
     802               2 :         PrintLine( fpSchema, "    </xs:extension>");
     803               2 :         PrintLine( fpSchema, "  </xs:complexContent>");
     804               2 :         PrintLine( fpSchema, "</xs:complexType>" );
     805                 :     } /* next layer */
     806                 : 
     807               2 :     PrintLine( fpSchema, "</xs:schema>" );
     808                 : 
     809                 : /* ==================================================================== */
     810                 : /*      Move schema to the start of the file.                           */
     811                 : /* ==================================================================== */
     812               2 :     if( bFpOutputIsStdout )
     813                 :     {
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      Read the schema into memory.                                    */
     816                 : /* -------------------------------------------------------------------- */
     817               0 :         int nSchemaSize = VSIFTellL( fpOutput ) - nSchemaStart;
     818               0 :         char *pszSchema = (char *) CPLMalloc(nSchemaSize+1);
     819                 :     
     820               0 :         VSIFSeekL( fpOutput, nSchemaStart, SEEK_SET );
     821                 : 
     822               0 :         VSIFReadL( pszSchema, 1, nSchemaSize, fpOutput );
     823               0 :         pszSchema[nSchemaSize] = '\0';
     824                 :     
     825                 : /* -------------------------------------------------------------------- */
     826                 : /*      Move file data down by "schema size" bytes from after <?xml>    */
     827                 : /*      header so we have room insert the schema.  Move in pretty       */
     828                 : /*      big chunks.                                                     */
     829                 : /* -------------------------------------------------------------------- */
     830               0 :         int nChunkSize = MIN(nSchemaStart-nSchemaInsertLocation,250000);
     831               0 :         char *pszChunk = (char *) CPLMalloc(nChunkSize);
     832               0 :         int nEndOfUnmovedData = nSchemaStart;
     833                 : 
     834               0 :         for( nEndOfUnmovedData = nSchemaStart;
     835                 :              nEndOfUnmovedData > nSchemaInsertLocation; )
     836                 :         {
     837                 :             int nBytesToMove = 
     838               0 :                 MIN(nChunkSize, nEndOfUnmovedData - nSchemaInsertLocation );
     839                 : 
     840               0 :             VSIFSeekL( fpOutput, nEndOfUnmovedData - nBytesToMove, SEEK_SET );
     841               0 :             VSIFReadL( pszChunk, 1, nBytesToMove, fpOutput );
     842                 :             VSIFSeekL( fpOutput, nEndOfUnmovedData - nBytesToMove + nSchemaSize, 
     843               0 :                       SEEK_SET );
     844               0 :             VSIFWriteL( pszChunk, 1, nBytesToMove, fpOutput );
     845                 :         
     846               0 :             nEndOfUnmovedData -= nBytesToMove;
     847                 :         }
     848                 : 
     849               0 :         CPLFree( pszChunk );
     850                 : 
     851                 : /* -------------------------------------------------------------------- */
     852                 : /*      Write the schema in the opened slot.                            */
     853                 : /* -------------------------------------------------------------------- */
     854               0 :         VSIFSeekL( fpOutput, nSchemaInsertLocation, SEEK_SET );
     855               0 :         VSIFWriteL( pszSchema, 1, nSchemaSize, fpOutput );
     856                 : 
     857               0 :         VSIFSeekL( fpOutput, 0, SEEK_END );
     858                 : 
     859               0 :         nBoundedByLocation += nSchemaSize;
     860                 :     }
     861                 : /* -------------------------------------------------------------------- */
     862                 : /*      Close external schema files.                                    */
     863                 : /* -------------------------------------------------------------------- */
     864                 :     else
     865               2 :         VSIFCloseL( fpSchema );
     866                 : }
     867                 : 
     868                 : 
     869                 : /************************************************************************/
     870                 : /*                            PrintLine()                               */
     871                 : /************************************************************************/
     872                 : 
     873             120 : void OGRGMLDataSource::PrintLine(FILE* fp, const char *fmt, ...)
     874                 : {
     875             120 :     CPLString osWork;
     876                 :     va_list args;
     877                 : 
     878             120 :     va_start( args, fmt );
     879             120 :     osWork.vPrintf( fmt, args );
     880             120 :     va_end( args );
     881                 : 
     882                 : #ifdef WIN32
     883                 :     const char* pszEOL = "\r\n";
     884                 : #else
     885             120 :     const char* pszEOL = "\n";
     886                 : #endif
     887                 : 
     888             120 :     VSIFPrintfL(fp, "%s%s", osWork.c_str(), pszEOL);
     889             120 : }

Generated by: LTP GCOV extension version 1.5