LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - ogrgmldatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 648 528 81.5 %
Date: 2011-12-18 Functions: 15 12 80.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgmldatasource.cpp 23573 2011-12-14 12:13:48Z 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                 :  * Contributor: Alessandro Furieri, a.furieri@lqt.it
      31                 :  * Portions of this module implenting GML_SKIP_RESOLVE_ELEMS HUGE
      32                 :  * Developed for Faunalia ( http://www.faunalia.it) with funding from 
      33                 :  * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
      34                 :  *
      35                 :  ****************************************************************************/
      36                 : 
      37                 : #include "ogr_gml.h"
      38                 : #include "parsexsd.h"
      39                 : #include "cpl_conv.h"
      40                 : #include "cpl_string.h"
      41                 : #include "gmlutils.h"
      42                 : #include "ogr_p.h"
      43                 : 
      44                 : #include <vector>
      45                 : 
      46                 : CPL_CVSID("$Id: ogrgmldatasource.cpp 23573 2011-12-14 12:13:48Z rouault $");
      47                 : 
      48                 : /************************************************************************/
      49                 : /*                         OGRGMLDataSource()                         */
      50                 : /************************************************************************/
      51                 : 
      52             308 : OGRGMLDataSource::OGRGMLDataSource()
      53                 : 
      54                 : {
      55             308 :     pszName = NULL;
      56             308 :     papoLayers = NULL;
      57             308 :     nLayers = 0;
      58                 : 
      59             308 :     poReader = NULL;
      60             308 :     fpOutput = NULL;
      61             308 :     bFpOutputIsNonSeekable = FALSE;
      62             308 :     bFpOutputSingleFile = FALSE;
      63             308 :     bIsOutputGML3 = FALSE;
      64             308 :     bIsOutputGML3Deegree = FALSE;
      65             308 :     bIsOutputGML32 = FALSE;
      66             308 :     bIsLongSRSRequired = FALSE;
      67             308 :     bWriteSpaceIndentation = TRUE;
      68                 : 
      69             308 :     papszCreateOptions = NULL;
      70             308 :     bOutIsTempFile = FALSE;
      71                 : 
      72             308 :     bExposeGMLId = FALSE;
      73             308 :     bExposeFid = FALSE;
      74             308 :     nSchemaInsertLocation = -1;
      75             308 :     nBoundedByLocation = -1;
      76             308 :     bBBOX3D = FALSE;
      77                 : 
      78             308 :     poGlobalSRS = NULL;
      79             308 :     bIsWFS = FALSE;
      80                 : 
      81             308 :     eReadMode = STANDARD;
      82             308 :     poStoredGMLFeature = NULL;
      83             308 :     poLastReadLayer = NULL;
      84                 : 
      85             308 :     m_bInvertAxisOrderIfLatLong = FALSE;
      86             308 :     m_bConsiderEPSGAsURN = FALSE;
      87             308 :     m_bGetSecondaryGeometryOption = FALSE;
      88             308 : }
      89                 : 
      90                 : /************************************************************************/
      91                 : /*                        ~OGRGMLDataSource()                         */
      92                 : /************************************************************************/
      93                 : 
      94             308 : OGRGMLDataSource::~OGRGMLDataSource()
      95                 : 
      96                 : {
      97                 : 
      98             308 :     if( fpOutput != NULL )
      99                 :     {
     100                 :         PrintLine( fpOutput, "%s", 
     101               9 :                     "</ogr:FeatureCollection>" );
     102                 : 
     103               9 :         if( bFpOutputIsNonSeekable)
     104                 :         {
     105               0 :             VSIFCloseL( fpOutput );
     106               0 :             fpOutput = NULL;
     107                 :         }
     108                 : 
     109               9 :         InsertHeader();
     110                 : 
     111               9 :         if( !bFpOutputIsNonSeekable
     112                 :             && nBoundedByLocation != -1
     113                 :             && sBoundingRect.IsInit() 
     114                 :             && VSIFSeekL( fpOutput, nBoundedByLocation, SEEK_SET ) == 0 )
     115                 :         {
     116               5 :             if (IsGML3Output())
     117                 :             {
     118               4 :                 int bCoordSwap = FALSE;
     119                 :                 char* pszSRSName;
     120               4 :                 if (poGlobalSRS)
     121               4 :                     pszSRSName = GML_GetSRSName(poGlobalSRS, IsLongSRSRequired(), &bCoordSwap);
     122                 :                 else
     123               0 :                     pszSRSName = CPLStrdup("");
     124                 :                 char szLowerCorner[75], szUpperCorner[75];
     125               4 :                 if (bCoordSwap)
     126                 :                 {
     127               3 :                     OGRMakeWktCoordinate(szLowerCorner, sBoundingRect.MinY, sBoundingRect.MinX, sBoundingRect.MinZ, (bBBOX3D) ? 3 : 2);
     128               3 :                     OGRMakeWktCoordinate(szUpperCorner, sBoundingRect.MaxY, sBoundingRect.MaxX, sBoundingRect.MaxZ, (bBBOX3D) ? 3 : 2);
     129                 :                 }
     130                 :                 else
     131                 :                 {
     132               1 :                     OGRMakeWktCoordinate(szLowerCorner, sBoundingRect.MinX, sBoundingRect.MinY, sBoundingRect.MinZ, (bBBOX3D) ? 3 : 2);
     133               1 :                     OGRMakeWktCoordinate(szUpperCorner, sBoundingRect.MaxX, sBoundingRect.MaxY, sBoundingRect.MaxZ, (bBBOX3D) ? 3 : 2);
     134                 :                 }
     135               4 :                 if (bWriteSpaceIndentation)
     136               4 :                     VSIFPrintfL( fpOutput, "  ");
     137                 :                 PrintLine( fpOutput, "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner></gml:Envelope></gml:boundedBy>",
     138               4 :                            (bBBOX3D) ? " srsDimension=\"3\"" : "", pszSRSName, szLowerCorner, szUpperCorner);
     139               4 :                 CPLFree(pszSRSName);
     140                 :             }
     141                 :             else
     142                 :             {
     143               1 :                 if (bWriteSpaceIndentation)
     144               1 :                     VSIFPrintfL( fpOutput, "  ");
     145               1 :                 PrintLine( fpOutput, "<gml:boundedBy>" );
     146               1 :                 if (bWriteSpaceIndentation)
     147               1 :                     VSIFPrintfL( fpOutput, "    ");
     148               1 :                 PrintLine( fpOutput, "<gml:Box>" );
     149               1 :                 if (bWriteSpaceIndentation)
     150               1 :                     VSIFPrintfL( fpOutput, "      ");
     151                 :                 VSIFPrintfL( fpOutput,
     152                 :                             "<gml:coord><gml:X>%.16g</gml:X>"
     153                 :                             "<gml:Y>%.16g</gml:Y>",
     154               1 :                             sBoundingRect.MinX, sBoundingRect.MinY );
     155               1 :                 if (bBBOX3D)
     156                 :                     VSIFPrintfL( fpOutput, "<gml:Z>%.16g</gml:Z>",
     157               1 :                                sBoundingRect.MinZ );
     158               1 :                 PrintLine( fpOutput, "</gml:coord>");
     159               1 :                 if (bWriteSpaceIndentation)
     160               1 :                     VSIFPrintfL( fpOutput, "      ");
     161                 :                 VSIFPrintfL( fpOutput,
     162                 :                             "<gml:coord><gml:X>%.16g</gml:X>"
     163                 :                             "<gml:Y>%.16g</gml:Y>",
     164               1 :                             sBoundingRect.MaxX, sBoundingRect.MaxY );
     165               1 :                 if (bBBOX3D)
     166                 :                     VSIFPrintfL( fpOutput, "<gml:Z>%.16g</gml:Z>",
     167               1 :                                sBoundingRect.MaxZ );
     168               1 :                 PrintLine( fpOutput, "</gml:coord>");
     169               1 :                 if (bWriteSpaceIndentation)
     170               1 :                     VSIFPrintfL( fpOutput, "    ");
     171               1 :                 PrintLine( fpOutput, "</gml:Box>" );
     172               1 :                 if (bWriteSpaceIndentation)
     173               1 :                     VSIFPrintfL( fpOutput, "  ");
     174               1 :                 PrintLine( fpOutput, "</gml:boundedBy>" );
     175                 :             }
     176                 :         }
     177                 : 
     178               9 :         if (fpOutput)
     179               9 :             VSIFCloseL( fpOutput );
     180                 :     }
     181                 : 
     182             308 :     CSLDestroy( papszCreateOptions );
     183             308 :     CPLFree( pszName );
     184                 : 
     185             406 :     for( int i = 0; i < nLayers; i++ )
     186              98 :         delete papoLayers[i];
     187                 :     
     188             308 :     CPLFree( papoLayers );
     189                 : 
     190             308 :     if( poReader )
     191                 :     {
     192              67 :         if (bOutIsTempFile)
     193               0 :             VSIUnlink(poReader->GetSourceFileName());
     194              67 :         delete poReader;
     195                 :     }
     196                 : 
     197             308 :     delete poGlobalSRS;
     198                 : 
     199             308 :     delete poStoredGMLFeature;
     200             308 : }
     201                 : 
     202                 : /************************************************************************/
     203                 : /*                                Open()                                */
     204                 : /************************************************************************/
     205                 : 
     206             299 : int OGRGMLDataSource::Open( const char * pszNewName, int bTestOpen )
     207                 : 
     208                 : {
     209                 :     VSILFILE   *fp;
     210                 :     char        szHeader[2048];
     211             299 :     int         nNumberOfFeatures = 0;
     212             299 :     CPLString   osWithVsiGzip;
     213                 : 
     214             299 :     pszName = CPLStrdup( pszNewName );
     215                 : 
     216                 : /* -------------------------------------------------------------------- */
     217                 : /*      Open the source file.                                           */
     218                 : /* -------------------------------------------------------------------- */
     219             299 :     fp = VSIFOpenL( pszNewName, "r" );
     220             299 :     if( fp == NULL )
     221                 :     {
     222              67 :         if( !bTestOpen )
     223                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     224                 :                       "Failed to open GML file `%s'.", 
     225               0 :                       pszNewName );
     226                 : 
     227              67 :         return FALSE;
     228                 :     }
     229                 : 
     230             232 :     int bExpatCompatibleEncoding = FALSE;
     231             232 :     int bHas3D = FALSE;
     232             232 :     int bHintConsiderEPSGAsURN = FALSE;
     233                 : 
     234                 : /* -------------------------------------------------------------------- */
     235                 : /*      If we aren't sure it is GML, load a header chunk and check      */
     236                 : /*      for signs it is GML                                             */
     237                 : /* -------------------------------------------------------------------- */
     238             232 :     if( bTestOpen )
     239                 :     {
     240             232 :         size_t nRead = VSIFReadL( szHeader, 1, sizeof(szHeader), fp );
     241             232 :         if (nRead <= 0)
     242                 :         {
     243               4 :             VSIFCloseL( fp );
     244               4 :             return FALSE;
     245                 :         }
     246             228 :         szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
     247                 : 
     248                 :         /* Might be a OS-Mastermap gzipped GML, so let be nice and try to open */
     249                 :         /* it transparently with /vsigzip/ */
     250             228 :         if ( ((GByte*)szHeader)[0] == 0x1f && ((GByte*)szHeader)[1] == 0x8b &&
     251                 :              EQUAL(CPLGetExtension(pszNewName), "gz") &&
     252                 :              strncmp(pszNewName, "/vsigzip/", strlen("/vsigzip/")) != 0 )
     253                 :         {
     254               0 :             VSIFCloseL( fp );
     255               0 :             osWithVsiGzip = "/vsigzip/";
     256               0 :             osWithVsiGzip += pszNewName;
     257                 : 
     258               0 :             pszNewName = osWithVsiGzip;
     259                 : 
     260               0 :             fp = VSIFOpenL( pszNewName, "r" );
     261               0 :             if( fp == NULL )
     262               0 :                 return FALSE;
     263                 : 
     264               0 :             nRead = VSIFReadL( szHeader, 1, sizeof(szHeader), fp );
     265               0 :             if (nRead <= 0)
     266                 :             {
     267               0 :                 VSIFCloseL( fp );
     268               0 :                 return FALSE;
     269                 :             }
     270               0 :             szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
     271                 :         }
     272                 : 
     273                 : /* -------------------------------------------------------------------- */
     274                 : /*      Check for a UTF-8 BOM and skip if found                         */
     275                 : /*                                                                      */
     276                 : /*      TODO: BOM is variable-lenght parameter and depends on encoding. */
     277                 : /*            Add BOM detection for other encodings.                    */
     278                 : /* -------------------------------------------------------------------- */
     279                 : 
     280                 :         // Used to skip to actual beginning of XML data
     281             228 :         char* szPtr = szHeader;
     282                 : 
     283             230 :         if( ( (unsigned char)szHeader[0] == 0xEF )
     284               1 :             && ( (unsigned char)szHeader[1] == 0xBB )
     285               1 :             && ( (unsigned char)szHeader[2] == 0xBF) )
     286                 :         {
     287               1 :             szPtr += 3;
     288                 :         }
     289                 : 
     290             228 :         const char* pszEncoding = strstr(szPtr, "encoding=");
     291             228 :         if (pszEncoding)
     292             158 :             bExpatCompatibleEncoding = (pszEncoding[9] == '\'' || pszEncoding[9] == '"') &&
     293                 :                                        (EQUALN(pszEncoding + 10, "UTF-8", 5) ||
     294             239 :                                         EQUALN(pszEncoding + 10, "ISO-8859-1", 10));
     295                 :         else
     296             147 :             bExpatCompatibleEncoding = TRUE; /* utf-8 is the default */
     297                 : 
     298             228 :         bHas3D = strstr(szPtr, "srsDimension=\"3\"") != NULL || strstr(szPtr, "<gml:Z>") != NULL;
     299                 : 
     300                 : /* -------------------------------------------------------------------- */
     301                 : /*      Here, we expect the opening chevrons of GML tree root element   */
     302                 : /* -------------------------------------------------------------------- */
     303             228 :         if( szPtr[0] != '<' 
     304                 :             || strstr(szPtr,"opengis.net/gml") == NULL )
     305                 :         {
     306             157 :             VSIFCloseL( fp );
     307             157 :             return FALSE;
     308                 :         }
     309                 : 
     310                 :         /* Ignore GeoRSS documents. They will be recognized by the GeoRSS driver */
     311              71 :         if( strstr(szPtr, "<rss") != NULL && strstr(szPtr, "xmlns:georss") != NULL )
     312                 :         {
     313               4 :             VSIFCloseL( fp );
     314               4 :             return FALSE;
     315                 :         }
     316                 : 
     317                 :         /* Small optimization: if we parse a <wfs:FeatureCollection>  and */
     318                 :         /* that numberOfFeatures is set, we can use it to set the FeatureCount */
     319                 :         /* but *ONLY* if there's just one class ! */
     320              67 :         const char* pszFeatureCollection = strstr(szPtr, "wfs:FeatureCollection");
     321              67 :         if (pszFeatureCollection == NULL)
     322              45 :             pszFeatureCollection = strstr(szPtr, "gml:FeatureCollection"); /* GML 3.2.1 output */
     323              67 :         if (pszFeatureCollection)
     324                 :         {
     325              32 :             bExposeGMLId = TRUE;
     326              32 :             bIsWFS = TRUE;
     327              32 :             const char* pszNumberOfFeatures = strstr(szPtr, "numberOfFeatures=");
     328              32 :             if (pszNumberOfFeatures)
     329                 :             {
     330              14 :                 pszNumberOfFeatures += 17;
     331              14 :                 char ch = pszNumberOfFeatures[0];
     332              14 :                 if ((ch == '\'' || ch == '"') && strchr(pszNumberOfFeatures + 1, ch) != NULL)
     333                 :                 {
     334              14 :                     nNumberOfFeatures = atoi(pszNumberOfFeatures + 1);
     335                 :                 }
     336                 :             }
     337              18 :             else if ((pszNumberOfFeatures = strstr(szPtr, "numberReturned=")) != NULL) /* WFS 2.0.0 */
     338                 :             {
     339               2 :                 pszNumberOfFeatures += 15;
     340               2 :                 char ch = pszNumberOfFeatures[0];
     341               2 :                 if ((ch == '\'' || ch == '"') && strchr(pszNumberOfFeatures + 1, ch) != NULL)
     342                 :                 {
     343                 :                     /* 'unknown' might be a valid value in a corrected version of WFS 2.0 */
     344                 :                     /* but it will also evaluate to 0, that is considered as unknown, so nothing */
     345                 :                     /* particular to do */
     346               2 :                     nNumberOfFeatures = atoi(pszNumberOfFeatures + 1);
     347                 :                 }
     348                 :             }
     349                 :         }
     350              35 :         else if (strncmp(pszNewName, "/vsimem/tempwfs_", strlen("/vsimem/tempwfs_")) == 0)
     351                 :         {
     352                 :             /* http://regis.intergraph.com/wfs/dcmetro/request.asp? returns a <G:FeatureCollection> */
     353                 :             /* Who knows what servers can return ? Ok, so when in the context of the WFS driver */
     354                 :             /* always expose the gml:id to avoid later crashes */
     355               0 :             bExposeGMLId = TRUE;
     356               0 :             bIsWFS = TRUE;
     357                 :         }
     358                 :         else
     359                 :         {
     360                 :             bExposeGMLId = strstr(szPtr, " gml:id=\"") != NULL ||
     361              35 :                            strstr(szPtr, " gml:id='") != NULL;
     362                 :             bExposeFid = strstr(szPtr, " fid=\"") != NULL ||
     363              35 :                          strstr(szPtr, " fid='") != NULL;
     364                 :             
     365              35 :             const char* pszExposeGMLId = CPLGetConfigOption("GML_EXPOSE_GML_ID", NULL);
     366              35 :             if (pszExposeGMLId)
     367               0 :                 bExposeGMLId = CSLTestBoolean(pszExposeGMLId);
     368                 : 
     369              35 :             const char* pszExposeFid = CPLGetConfigOption("GML_EXPOSE_FID", NULL);
     370              35 :             if (pszExposeFid)
     371               1 :                 bExposeFid = CSLTestBoolean(pszExposeFid);
     372                 :         }
     373                 : 
     374              67 :         bHintConsiderEPSGAsURN = strstr(szPtr, "xmlns:fme=\"http://www.safe.com/gml/fme\"") != NULL;
     375                 :     }
     376                 :     
     377                 : /* -------------------------------------------------------------------- */
     378                 : /*      We assume now that it is GML.  Close and instantiate a          */
     379                 : /*      GMLReader on it.                                                */
     380                 : /* -------------------------------------------------------------------- */
     381              67 :     VSIFCloseL( fp );
     382                 : 
     383              67 :     const char* pszReadMode = CPLGetConfigOption("GML_READ_MODE", NULL);
     384             131 :     if (pszReadMode == NULL || EQUAL(pszReadMode, "STANDARD"))
     385              64 :         eReadMode = STANDARD;
     386               3 :     else if (EQUAL(pszReadMode, "SEQUENTIAL_LAYERS"))
     387               2 :         eReadMode = SEQUENTIAL_LAYERS;
     388               1 :     else if (EQUAL(pszReadMode, "INTERLEAVED_LAYERS"))
     389               1 :         eReadMode = INTERLEAVED_LAYERS;
     390                 :     else
     391                 :     {
     392               0 :         CPLDebug("GML", "Unrecognized value for GML_READ_MODE configuration option.");
     393                 :     }
     394                 : 
     395                 :     m_bInvertAxisOrderIfLatLong = CSLTestBoolean(
     396              67 :         CPLGetConfigOption("GML_INVERT_AXIS_ORDER_IF_LAT_LONG", "YES"));
     397                 : 
     398                 :     const char* pszConsiderEPSGAsURN =
     399              67 :         CPLGetConfigOption("GML_CONSIDER_EPSG_AS_URN", NULL);
     400              67 :     if (pszConsiderEPSGAsURN != NULL)
     401               0 :         m_bConsiderEPSGAsURN = CSLTestBoolean(pszConsiderEPSGAsURN);
     402              67 :     else if (bHintConsiderEPSGAsURN)
     403                 :     {
     404                 :         /* GML produced by FME (at least CanVec GML) seem to honour EPSG axis ordering */
     405               5 :         CPLDebug("GML", "FME-produced GML --> consider that GML_CONSIDER_EPSG_AS_URN is set to YES");
     406               5 :         m_bConsiderEPSGAsURN = TRUE;
     407                 :     }
     408                 :     else
     409              62 :         m_bConsiderEPSGAsURN = FALSE;
     410                 : 
     411              67 :     m_bGetSecondaryGeometryOption = CSLTestBoolean(CPLGetConfigOption("GML_GET_SECONDARY_GEOM", "NO"));
     412                 : 
     413                 :     /* EXPAT is faster than Xerces, so when it is safe to use it, use it ! */
     414                 :     /* The only interest of Xerces is for rare encodings that Expat doesn't handle */
     415                 :     /* but UTF-8 is well handled by Expat */
     416              67 :     int bUseExpatParserPreferably = bExpatCompatibleEncoding;
     417                 : 
     418                 :     /* Override default choice */
     419              67 :     const char* pszGMLParser = CPLGetConfigOption("GML_PARSER", NULL);
     420              67 :     if (pszGMLParser)
     421                 :     {
     422               0 :         if (EQUAL(pszGMLParser, "EXPAT"))
     423               0 :             bUseExpatParserPreferably = TRUE;
     424               0 :         else if (EQUAL(pszGMLParser, "XERCES"))
     425               0 :             bUseExpatParserPreferably = FALSE;
     426                 :     }
     427                 : 
     428                 :     poReader = CreateGMLReader( bUseExpatParserPreferably,
     429                 :                                 m_bInvertAxisOrderIfLatLong,
     430                 :                                 m_bConsiderEPSGAsURN,
     431              67 :                                 m_bGetSecondaryGeometryOption );
     432              67 :     if( poReader == NULL )
     433                 :     {
     434                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     435                 :                   "File %s appears to be GML but the GML reader can't\n"
     436                 :                   "be instantiated, likely because Xerces or Expat support wasn't\n"
     437                 :                   "configured in.", 
     438               0 :                   pszNewName );
     439               0 :         return FALSE;
     440                 :     }
     441                 : 
     442              67 :     poReader->SetSourceFile( pszNewName );
     443                 :     
     444                 : /* -------------------------------------------------------------------- */
     445                 : /*      Resolve the xlinks in the source file and save it with the      */
     446                 : /*      extension ".resolved.gml". The source file will to set to that. */
     447                 : /* -------------------------------------------------------------------- */
     448                 : 
     449              67 :     char *pszXlinkResolvedFilename = NULL;
     450              67 :     const char *pszOption = CPLGetConfigOption("GML_SAVE_RESOLVED_TO", NULL);
     451              67 :     int bResolve = TRUE;
     452              67 :     int bHugeFile = FALSE;
     453              67 :     if( pszOption != NULL && EQUALN( pszOption, "SAME", 4 ) )
     454                 :     {
     455                 :         // "SAME" will overwrite the existing gml file
     456               0 :         pszXlinkResolvedFilename = CPLStrdup( pszNewName );
     457                 :     }
     458              67 :     else if( pszOption != NULL &&
     459                 :              CPLStrnlen( pszOption, 5 ) >= 5 &&
     460                 :              EQUALN( pszOption - 4 + strlen( pszOption ), ".gml", 4 ) )
     461                 :     {
     462                 :         // Any string ending with ".gml" will try and write to it
     463               2 :         pszXlinkResolvedFilename = CPLStrdup( pszOption );
     464                 :     }
     465                 :     else
     466                 :     {
     467                 :         // When no option is given or is not recognised,
     468                 :         // use the same file name with the extension changed to .resolved.gml
     469                 :         pszXlinkResolvedFilename = CPLStrdup(
     470              65 :                             CPLResetExtension( pszNewName, "resolved.gml" ) );
     471                 : 
     472                 :         // Check if the file already exists.
     473                 :         VSIStatBufL sResStatBuf, sGMLStatBuf;
     474              65 :         if( VSIStatL( pszXlinkResolvedFilename, &sResStatBuf ) == 0 )
     475                 :         {
     476               2 :             VSIStatL( pszNewName, &sGMLStatBuf );
     477               2 :             if( sGMLStatBuf.st_mtime > sResStatBuf.st_mtime )
     478                 :             {
     479                 :                 CPLDebug( "GML", 
     480                 :                           "Found %s but ignoring because it appears\n"
     481                 :                           "be older than the associated GML file.", 
     482               0 :                           pszXlinkResolvedFilename );
     483                 :             }
     484                 :             else
     485                 :             {
     486               2 :                 poReader->SetSourceFile( pszXlinkResolvedFilename );
     487               2 :                 bResolve = FALSE;
     488                 :             }
     489                 :         }
     490                 :     }
     491                 : 
     492                 :     const char *pszSkipOption = CPLGetConfigOption( "GML_SKIP_RESOLVE_ELEMS",
     493              67 :                                                     "ALL");
     494              67 :     char **papszSkip = NULL;
     495              67 :     if( EQUAL( pszSkipOption, "ALL" ) )
     496              63 :         bResolve = FALSE;
     497               4 :     else if( EQUAL( pszSkipOption, "HUGE" ) )//exactly as NONE, but intended for HUGE files
     498               1 :         bHugeFile = TRUE;
     499               3 :     else if( !EQUAL( pszSkipOption, "NONE" ) )//use this to resolve everything
     500                 :         papszSkip = CSLTokenizeString2( pszSkipOption, ",",
     501                 :                                            CSLT_STRIPLEADSPACES |
     502               1 :                                            CSLT_STRIPENDSPACES );
     503                 :     const char *pszGFSFilename;
     504                 :     VSIStatBufL sGFSStatBuf, sGMLStatBuf;
     505              67 :     int         bHaveSchema = FALSE;
     506              67 :     int         bSchemaDone = FALSE;
     507                 :  
     508                 : /* -------------------------------------------------------------------- */
     509                 : /*      Is some GML Feature Schema (.gfs) TEMPLATE required ?           */
     510                 : /* -------------------------------------------------------------------- */
     511                 :     const char *pszGFSTemplateName = 
     512              67 :                 CPLGetConfigOption( "GML_GFS_TEMPLATE", NULL);
     513              67 :     if( pszGFSTemplateName != NULL )
     514                 :     {
     515                 :         /* attempting to load the GFS TEMPLATE */
     516               0 :         bHaveSchema = poReader->LoadClasses( pszGFSTemplateName );
     517                 :     } 
     518                 : 
     519              67 :     if( bResolve )
     520                 :     {
     521               4 :         if ( bHugeFile )
     522                 :         {
     523               1 :             bSchemaDone = TRUE;
     524                 :             int bSqliteIsTempFile =
     525               1 :                 CSLTestBoolean(CPLGetConfigOption( "GML_HUGE_TEMPFILE", "YES"));
     526               1 :             int iSqliteCacheMB = atoi(CPLGetConfigOption( "OGR_SQLITE_CACHE", "0"));
     527               2 :             if( poReader->HugeFileResolver( pszXlinkResolvedFilename,
     528                 :                                             bSqliteIsTempFile, 
     529               1 :                                             iSqliteCacheMB ) == FALSE )
     530                 :             {
     531                 :                 // we assume an errors have been reported.
     532               0 :                 return FALSE;
     533                 :             }
     534                 :         }
     535                 :         else
     536                 :         {
     537                 :             poReader->ResolveXlinks( pszXlinkResolvedFilename,
     538                 :                                      &bOutIsTempFile,
     539               3 :                                      papszSkip );
     540                 :         }
     541                 :     }
     542                 : 
     543              67 :     CPLFree( pszXlinkResolvedFilename );
     544              67 :     pszXlinkResolvedFilename = NULL;
     545              67 :     CSLDestroy( papszSkip );
     546              67 :     papszSkip = NULL;
     547                 : 
     548                 :     /* Is a prescan required ? */
     549              67 :     if( bHaveSchema && !bSchemaDone )
     550                 :     {
     551                 :         /* We must detect which layers are actually present in the .gml */
     552                 :         /* and how many features they have */
     553               0 :         if( !poReader->PrescanForTemplate() )
     554                 :         {
     555                 :             // we assume an errors have been reported.
     556               0 :             return FALSE;
     557                 :         }
     558                 :     }
     559                 : 
     560                 : /* -------------------------------------------------------------------- */
     561                 : /*      Can we find a GML Feature Schema (.gfs) for the input file?     */
     562                 : /* -------------------------------------------------------------------- */
     563              67 :     if( !bHaveSchema )
     564                 :     {
     565              67 :         pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
     566              67 :         if (strncmp(pszGFSFilename, "/vsigzip/", strlen("/vsigzip/")) == 0)
     567               0 :             pszGFSFilename += strlen("/vsigzip/");
     568              67 :         if( VSIStatL( pszGFSFilename, &sGFSStatBuf ) == 0 )
     569                 :         {
     570              15 :             VSIStatL( pszNewName, &sGMLStatBuf );
     571              15 :             if( sGMLStatBuf.st_mtime > sGFSStatBuf.st_mtime )
     572                 :             {
     573                 :                 CPLDebug( "GML", 
     574                 :                           "Found %s but ignoring because it appears\n"
     575                 :                           "be older than the associated GML file.", 
     576               0 :                           pszGFSFilename );
     577                 :             }
     578                 :             else
     579                 :             {
     580              15 :                 bHaveSchema = poReader->LoadClasses( pszGFSFilename );
     581              15 :                 if (bHaveSchema)
     582                 :                 {
     583                 :                     const char *pszXSDFilename;
     584              15 :                     pszXSDFilename = CPLResetExtension( pszNewName, "xsd" );
     585              15 :                     if( VSIStatExL( pszXSDFilename, &sGMLStatBuf,
     586                 :                                     VSI_STAT_EXISTS_FLAG ) == 0 )
     587                 :                     {
     588                 :                         CPLDebug("GML", "Using %s file, ignoring %s",
     589               0 :                                  pszGFSFilename, pszXSDFilename);
     590                 :                     }
     591                 :                 }
     592                 :             }
     593                 :         }
     594                 :     }
     595                 : 
     596                 : /* -------------------------------------------------------------------- */
     597                 : /*      Can we find an xsd which might conform to tbe GML3 Level 0      */
     598                 : /*      profile?  We really ought to look for it based on the rules     */
     599                 : /*      schemaLocation in the GML feature collection but for now we     */
     600                 : /*      just hopes it is in the same director with the same name.       */
     601                 : /* -------------------------------------------------------------------- */
     602                 :     const char *pszXSDFilename;
     603              67 :     int bHasFoundXSD = FALSE;
     604                 : 
     605              67 :     if( !bHaveSchema )
     606                 :     {
     607              52 :         pszXSDFilename = CPLResetExtension( pszNewName, "xsd" );
     608              52 :         if( VSIStatL( pszXSDFilename, &sGMLStatBuf ) == 0 )
     609                 :         {
     610              31 :             bHasFoundXSD = TRUE;
     611                 : 
     612              31 :             std::vector<GMLFeatureClass*> aosClasses;
     613              31 :             bHaveSchema = GMLParseXSD( pszXSDFilename, aosClasses );
     614              31 :             if (bHaveSchema)
     615                 :             {
     616              31 :                 std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
     617              31 :                 std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
     618              99 :                 while (iter != eiter)
     619                 :                 {
     620              37 :                     GMLFeatureClass* poClass = *iter;
     621              37 :                     iter ++;
     622                 : 
     623                 :                     /* We have no way of knowing if the geometry type is 25D */
     624                 :                     /* when examining the xsd only, so if there was a hint */
     625                 :                     /* it is, we force to 25D */
     626              37 :                     if (bHas3D)
     627                 :                     {
     628                 :                         poClass->SetGeometryType(
     629               2 :                             poClass->GetGeometryType() | wkb25DBit);
     630                 :                     }
     631              37 :                     poReader->AddClass( poClass );
     632                 :                 }
     633              31 :                 poReader->SetClassListLocked( TRUE );
     634              31 :             }
     635                 :         }
     636                 :     }
     637                 : 
     638                 : /* -------------------------------------------------------------------- */
     639                 : /*      Force a first pass to establish the schema.  Eventually we      */
     640                 : /*      will have mechanisms for remembering the schema and related     */
     641                 : /*      information.                                                    */
     642                 : /* -------------------------------------------------------------------- */
     643              67 :     if( !bHaveSchema )
     644                 :     {
     645              21 :         if( !poReader->PrescanForSchema( TRUE ) )
     646                 :         {
     647                 :             // we assume an errors have been reported.
     648               1 :             return FALSE;
     649                 :         }
     650                 : 
     651              20 :         if( bHasFoundXSD )
     652                 :         {
     653                 :             CPLDebug("GML", "Generating %s file, ignoring %s",
     654               0 :                      pszGFSFilename, pszXSDFilename);
     655                 :         }
     656                 :     }
     657                 : 
     658              66 :     if (poReader->GetClassCount() > 1 && poReader->IsSequentialLayers() &&
     659                 :         pszReadMode == NULL)
     660                 :     {
     661               7 :         CPLDebug("GML", "Layers are monoblock. Using SEQUENTIAL_LAYERS read mode");
     662               7 :         eReadMode = SEQUENTIAL_LAYERS;
     663                 :     }
     664                 : 
     665                 : /* -------------------------------------------------------------------- */
     666                 : /*      Save the schema file if possible.  Don't make a fuss if we      */
     667                 : /*      can't ... could be read-only directory or something.            */
     668                 : /* -------------------------------------------------------------------- */
     669              66 :     if( !bHaveSchema && !poReader->HasStoppedParsing() &&
     670                 :         !EQUALN(pszNewName, "/vsitar/", strlen("/vsitar/")) &&
     671                 :         !EQUALN(pszNewName, "/vsizip/", strlen("/vsizip/")) &&
     672                 :         !EQUALN(pszNewName, "/vsigzip/vsi", strlen("/vsigzip/vsi")) &&
     673                 :         !EQUALN(pszNewName, "/vsigzip//vsi", strlen("/vsigzip//vsi")) &&
     674                 :         !EQUALN(pszNewName, "/vsicurl/", strlen("/vsicurl/")))
     675                 :     {
     676              20 :         VSILFILE    *fp = NULL;
     677                 : 
     678              20 :         pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
     679              20 :         if (strncmp(pszGFSFilename, "/vsigzip/", strlen("/vsigzip/")) == 0)
     680               0 :             pszGFSFilename += strlen("/vsigzip/");
     681                 : 
     682              20 :         if( VSIStatL( pszGFSFilename, &sGFSStatBuf ) != 0 
     683                 :             && (fp = VSIFOpenL( pszGFSFilename, "wt" )) != NULL )
     684                 :         {
     685              20 :             VSIFCloseL( fp );
     686              20 :             poReader->SaveClasses( pszGFSFilename );
     687                 :         }
     688                 :         else
     689                 :         {
     690                 :             CPLDebug("GML", 
     691                 :                      "Not saving %s files already exists or can't be created.",
     692               0 :                      pszGFSFilename );
     693                 :         }
     694                 :     }
     695                 : 
     696                 : /* -------------------------------------------------------------------- */
     697                 : /*      Translate the GMLFeatureClasses into layers.                    */
     698                 : /* -------------------------------------------------------------------- */
     699                 :     papoLayers = (OGRGMLLayer **)
     700              66 :         CPLCalloc( sizeof(OGRGMLLayer *), poReader->GetClassCount());
     701              66 :     nLayers = 0;
     702                 : 
     703              66 :     if (poReader->GetClassCount() == 1 && nNumberOfFeatures != 0)
     704                 :     {
     705              14 :         GMLFeatureClass *poClass = poReader->GetClass(0);
     706              14 :         int nFeatureCount = poClass->GetFeatureCount();
     707              14 :         if (nFeatureCount < 0)
     708                 :         {
     709              12 :             poClass->SetFeatureCount(nNumberOfFeatures);
     710                 :         }
     711               2 :         else if (nFeatureCount != nNumberOfFeatures)
     712                 :         {
     713               0 :             CPLDebug("GML", "Feature count in header, and actual feature count don't match");
     714                 :         }
     715                 :     }
     716                 : 
     717             221 :     while( nLayers < poReader->GetClassCount() )
     718                 :     {
     719              89 :         papoLayers[nLayers] = TranslateGMLSchema(poReader->GetClass(nLayers));
     720              89 :         nLayers++;
     721                 :     }
     722                 :     
     723                 : 
     724                 :     
     725              66 :     return TRUE;
     726                 : }
     727                 : 
     728                 : /************************************************************************/
     729                 : /*                         TranslateGMLSchema()                         */
     730                 : /************************************************************************/
     731                 : 
     732              89 : OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
     733                 : 
     734                 : {
     735                 :     OGRGMLLayer *poLayer;
     736                 :     OGRwkbGeometryType eGType 
     737              89 :         = (OGRwkbGeometryType) poClass->GetGeometryType();
     738                 : 
     739              89 :     if( poClass->GetFeatureCount() == 0 )
     740               0 :         eGType = wkbUnknown;
     741                 :     
     742                 : /* -------------------------------------------------------------------- */
     743                 : /*      Create an empty layer.                                          */
     744                 : /* -------------------------------------------------------------------- */
     745                 : 
     746              89 :     const char* pszSRSName = poClass->GetSRSName();
     747              89 :     OGRSpatialReference* poSRS = NULL;
     748              89 :     if (pszSRSName)
     749                 :     {
     750              21 :         poSRS = new OGRSpatialReference();
     751              21 :         if (poSRS->SetFromUserInput(pszSRSName) != OGRERR_NONE)
     752                 :         {
     753               0 :             delete poSRS;
     754               0 :             poSRS = NULL;
     755                 :         }
     756                 :     }
     757                 : 
     758                 :     poLayer = new OGRGMLLayer( poClass->GetName(), poSRS, FALSE,
     759              89 :                                eGType, this );
     760             110 :     delete poSRS;
     761                 : 
     762                 : /* -------------------------------------------------------------------- */
     763                 : /*      Added attributes (properties).                                  */
     764                 : /* -------------------------------------------------------------------- */
     765              89 :     if (bExposeGMLId)
     766                 :     {
     767              64 :         OGRFieldDefn oField( "gml_id", OFTString );
     768              64 :         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     769                 :     }
     770              25 :     else if (bExposeFid)
     771                 :     {
     772              18 :         OGRFieldDefn oField( "fid", OFTString );
     773              18 :         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     774                 :     }
     775                 : 
     776             338 :     for( int iField = 0; iField < poClass->GetPropertyCount(); iField++ )
     777                 :     {
     778             249 :         GMLPropertyDefn *poProperty = poClass->GetProperty( iField );
     779                 :         OGRFieldType eFType;
     780                 : 
     781             249 :         if( poProperty->GetType() == GMLPT_Untyped )
     782               0 :             eFType = OFTString;
     783             249 :         else if( poProperty->GetType() == GMLPT_String )
     784             112 :             eFType = OFTString;
     785             137 :         else if( poProperty->GetType() == GMLPT_Integer )
     786              89 :             eFType = OFTInteger;
     787              48 :         else if( poProperty->GetType() == GMLPT_Real )
     788              36 :             eFType = OFTReal;
     789              12 :         else if( poProperty->GetType() == GMLPT_StringList )
     790               6 :             eFType = OFTStringList;
     791               6 :         else if( poProperty->GetType() == GMLPT_IntegerList )
     792               3 :             eFType = OFTIntegerList;
     793               3 :         else if( poProperty->GetType() == GMLPT_RealList )
     794               3 :             eFType = OFTRealList;
     795                 :         else
     796               0 :             eFType = OFTString;
     797                 :         
     798             249 :         OGRFieldDefn oField( poProperty->GetName(), eFType );
     799             249 :         if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
     800               0 :           oField.SetName(poProperty->GetName()+4);
     801             249 :         if( poProperty->GetWidth() > 0 )
     802              74 :             oField.SetWidth( poProperty->GetWidth() );
     803             249 :         if( poProperty->GetPrecision() > 0 )
     804               5 :             oField.SetPrecision( poProperty->GetPrecision() );
     805                 : 
     806             249 :         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     807                 :     }
     808                 : 
     809              89 :     return poLayer;
     810                 : }
     811                 : 
     812                 : /************************************************************************/
     813                 : /*                         GetGlobalSRSName()                           */
     814                 : /************************************************************************/
     815                 : 
     816             307 : const char *OGRGMLDataSource::GetGlobalSRSName()
     817                 : {
     818             307 :     if (poReader->CanUseGlobalSRSName() || bIsWFS)
     819             232 :         return poReader->GetGlobalSRSName();
     820                 :     else
     821              75 :         return NULL;
     822                 : }
     823                 : 
     824                 : /************************************************************************/
     825                 : /*                               Create()                               */
     826                 : /************************************************************************/
     827                 : 
     828               9 : int OGRGMLDataSource::Create( const char *pszFilename, 
     829                 :                               char **papszOptions )
     830                 : 
     831                 : {
     832               9 :     if( fpOutput != NULL || poReader != NULL )
     833                 :     {
     834               0 :         CPLAssert( FALSE );
     835               0 :         return FALSE;
     836                 :     }
     837                 : 
     838               9 :     if( strcmp(pszFilename,"/dev/stdout") == 0 )
     839               0 :         pszFilename = "/vsistdout/";
     840                 : 
     841                 : /* -------------------------------------------------------------------- */
     842                 : /*      Read options                                                    */
     843                 : /* -------------------------------------------------------------------- */
     844                 : 
     845               9 :     CSLDestroy(papszCreateOptions);
     846               9 :     papszCreateOptions = CSLDuplicate(papszOptions);
     847                 : 
     848               9 :     const char* pszFormat = CSLFetchNameValue(papszCreateOptions, "FORMAT");
     849               9 :     bIsOutputGML3 = pszFormat && EQUAL(pszFormat, "GML3");
     850               9 :     bIsOutputGML3Deegree = pszFormat && EQUAL(pszFormat, "GML3Deegree");
     851               9 :     bIsOutputGML32 = pszFormat && EQUAL(pszFormat, "GML3.2");
     852               9 :     if (bIsOutputGML3Deegree || bIsOutputGML32)
     853               2 :         bIsOutputGML3 = TRUE;
     854                 : 
     855                 :     bIsLongSRSRequired =
     856               9 :         CSLTestBoolean(CSLFetchNameValueDef(papszCreateOptions, "GML3_LONGSRS", "YES"));
     857                 : 
     858                 :     bWriteSpaceIndentation =
     859               9 :         CSLTestBoolean(CSLFetchNameValueDef(papszCreateOptions, "SPACE_INDENTATION", "YES"));
     860                 : 
     861                 : /* -------------------------------------------------------------------- */
     862                 : /*      Create the output file.                                         */
     863                 : /* -------------------------------------------------------------------- */
     864               9 :     pszName = CPLStrdup( pszFilename );
     865                 : 
     866               9 :     if( strcmp(pszFilename,"/vsistdout/") == 0 ||
     867                 :         strncmp(pszFilename,"/vsigzip/", 9) == 0 )
     868                 :     {
     869               0 :         fpOutput = VSIFOpenL(pszFilename, "wb");
     870               0 :         bFpOutputIsNonSeekable = TRUE;
     871               0 :         bFpOutputSingleFile = TRUE;
     872                 :     }
     873               9 :     else if ( strncmp(pszFilename,"/vsizip/", 8) == 0)
     874                 :     {
     875               0 :         if (EQUAL(CPLGetExtension(pszFilename), "zip"))
     876                 :         {
     877               0 :             CPLFree(pszName);
     878               0 :             pszName = CPLStrdup(CPLFormFilename(pszFilename, "out.gml", NULL));
     879                 :         }
     880                 : 
     881               0 :         fpOutput = VSIFOpenL(pszName, "wb");
     882               0 :         bFpOutputIsNonSeekable = TRUE;
     883                 :     }
     884                 :     else
     885               9 :         fpOutput = VSIFOpenL( pszFilename, "wb+" );
     886               9 :     if( fpOutput == NULL )
     887                 :     {
     888                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     889                 :                   "Failed to create GML file %s.", 
     890               0 :                   pszFilename );
     891               0 :         return FALSE;
     892                 :     }
     893                 : 
     894                 : /* -------------------------------------------------------------------- */
     895                 : /*      Write out "standard" header.                                    */
     896                 : /* -------------------------------------------------------------------- */
     897                 :     PrintLine( fpOutput, "%s", 
     898               9 :                 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" );
     899                 : 
     900               9 :     if (!bFpOutputIsNonSeekable)
     901               9 :         nSchemaInsertLocation = (int) VSIFTellL( fpOutput );
     902                 : 
     903                 :     PrintLine( fpOutput, "%s", 
     904               9 :                 "<ogr:FeatureCollection" );
     905                 : 
     906               9 :     if (IsGML32Output())
     907                 :         PrintLine( fpOutput, "%s",
     908               1 :                 "     gml:id=\"aFeatureCollection\"" );
     909                 : 
     910                 : /* -------------------------------------------------------------------- */
     911                 : /*      Write out schema info if provided in creation options.          */
     912                 : /* -------------------------------------------------------------------- */
     913               9 :     const char *pszSchemaURI = CSLFetchNameValue(papszOptions,"XSISCHEMAURI");
     914               9 :     const char *pszSchemaOpt = CSLFetchNameValue( papszOptions, "XSISCHEMA" );
     915                 : 
     916               9 :     if( pszSchemaURI != NULL )
     917                 :     {
     918                 :         PrintLine( fpOutput, 
     919               0 :               "     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
     920                 :         PrintLine( fpOutput, 
     921                 :               "     xsi:schemaLocation=\"%s\"", 
     922               0 :                     CSLFetchNameValue( papszOptions, "XSISCHEMAURI" ) );
     923                 :     }
     924               9 :     else if( pszSchemaOpt == NULL || EQUAL(pszSchemaOpt,"EXTERNAL") )
     925                 :     {
     926               9 :         char *pszBasename = CPLStrdup(CPLGetBasename( pszName ));
     927                 : 
     928                 :         PrintLine( fpOutput, 
     929               9 :               "     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
     930                 :         PrintLine( fpOutput, 
     931                 :               "     xsi:schemaLocation=\"http://ogr.maptools.org/ %s\"", 
     932               9 :                     CPLResetExtension( pszBasename, "xsd" ) );
     933               9 :         CPLFree( pszBasename );
     934                 :     }
     935                 : 
     936                 :     PrintLine( fpOutput, "%s", 
     937               9 :                 "     xmlns:ogr=\"http://ogr.maptools.org/\"" );
     938               9 :     if (IsGML32Output())
     939                 :         PrintLine( fpOutput, "%s",
     940               1 :                 "     xmlns:gml=\"http://www.opengis.net/gml/3.2\">" );
     941                 :     else
     942                 :         PrintLine( fpOutput, "%s",
     943               8 :                     "     xmlns:gml=\"http://www.opengis.net/gml\">" );
     944                 : 
     945                 : /* -------------------------------------------------------------------- */
     946                 : /*      Should we initialize an area to place the boundedBy element?    */
     947                 : /*      We will need to seek back to fill it in.                        */
     948                 : /* -------------------------------------------------------------------- */
     949               9 :     if( CSLFetchBoolean( papszOptions, "BOUNDEDBY", TRUE ) &&
     950                 :         !bFpOutputIsNonSeekable )
     951                 :     {
     952               9 :         nBoundedByLocation = (int) VSIFTellL( fpOutput );
     953                 : 
     954               9 :         if( nBoundedByLocation != -1 )
     955               9 :             PrintLine( fpOutput, "%350s", "" );
     956                 :     }
     957                 :     else
     958               0 :         nBoundedByLocation = -1;
     959                 : 
     960               9 :     return TRUE;
     961                 : }
     962                 : 
     963                 : /************************************************************************/
     964                 : /*                            CreateLayer()                             */
     965                 : /************************************************************************/
     966                 : 
     967                 : OGRLayer *
     968               9 : OGRGMLDataSource::CreateLayer( const char * pszLayerName,
     969                 :                                OGRSpatialReference *poSRS,
     970                 :                                OGRwkbGeometryType eType,
     971                 :                                char ** papszOptions )
     972                 : 
     973                 : {
     974                 : /* -------------------------------------------------------------------- */
     975                 : /*      Verify we are in update mode.                                   */
     976                 : /* -------------------------------------------------------------------- */
     977               9 :     if( fpOutput == NULL )
     978                 :     {
     979                 :         CPLError( CE_Failure, CPLE_NoWriteAccess,
     980                 :                   "Data source %s opened for read access.\n"
     981                 :                   "New layer %s cannot be created.\n",
     982               0 :                   pszName, pszLayerName );
     983                 : 
     984               0 :         return NULL;
     985                 :     }
     986                 : 
     987                 : /* -------------------------------------------------------------------- */
     988                 : /*      Ensure name is safe as an element name.                         */
     989                 : /* -------------------------------------------------------------------- */
     990               9 :     char *pszCleanLayerName = CPLStrdup( pszLayerName );
     991                 : 
     992               9 :     CPLCleanXMLElementName( pszCleanLayerName );
     993               9 :     if( strcmp(pszCleanLayerName,pszLayerName) != 0 )
     994                 :     {
     995                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     996                 :                   "Layer name '%s' adjusted to '%s' for XML validity.",
     997               0 :                   pszLayerName, pszCleanLayerName );
     998                 :     }
     999                 : 
    1000                 : /* -------------------------------------------------------------------- */
    1001                 : /*      Set or check validity of global SRS.                            */
    1002                 : /* -------------------------------------------------------------------- */
    1003               9 :     if (nLayers == 0)
    1004                 :     {
    1005               9 :         if (poSRS)
    1006               5 :             poGlobalSRS = poSRS->Clone();
    1007                 :     }
    1008                 :     else
    1009                 :     {
    1010               0 :         if (poSRS == NULL ||
    1011                 :             (poGlobalSRS != NULL && poSRS->IsSame(poGlobalSRS)))
    1012                 :         {
    1013               0 :             delete poGlobalSRS;
    1014               0 :             poGlobalSRS = NULL;
    1015                 :         }
    1016                 :     }
    1017                 : 
    1018                 : /* -------------------------------------------------------------------- */
    1019                 : /*      Create the layer object.                                        */
    1020                 : /* -------------------------------------------------------------------- */
    1021                 :     OGRGMLLayer *poLayer;
    1022                 : 
    1023               9 :     poLayer = new OGRGMLLayer( pszCleanLayerName, poSRS, TRUE, eType, this );
    1024                 : 
    1025               9 :     CPLFree( pszCleanLayerName );
    1026                 : 
    1027                 : /* -------------------------------------------------------------------- */
    1028                 : /*      Add layer to data source layer list.                            */
    1029                 : /* -------------------------------------------------------------------- */
    1030                 :     papoLayers = (OGRGMLLayer **)
    1031               9 :         CPLRealloc( papoLayers,  sizeof(OGRGMLLayer *) * (nLayers+1) );
    1032                 :     
    1033               9 :     papoLayers[nLayers++] = poLayer;
    1034                 : 
    1035               9 :     return poLayer;
    1036                 : }
    1037                 : 
    1038                 : /************************************************************************/
    1039                 : /*                           TestCapability()                           */
    1040                 : /************************************************************************/
    1041                 : 
    1042               3 : int OGRGMLDataSource::TestCapability( const char * pszCap )
    1043                 : 
    1044                 : {
    1045               3 :     if( EQUAL(pszCap,ODsCCreateLayer) )
    1046               3 :         return TRUE;
    1047                 :     else
    1048               0 :         return FALSE;
    1049                 : }
    1050                 : 
    1051                 : /************************************************************************/
    1052                 : /*                              GetLayer()                              */
    1053                 : /************************************************************************/
    1054                 : 
    1055             115 : OGRLayer *OGRGMLDataSource::GetLayer( int iLayer )
    1056                 : 
    1057                 : {
    1058             115 :     if( iLayer < 0 || iLayer >= nLayers )
    1059               0 :         return NULL;
    1060                 :     else
    1061             115 :         return papoLayers[iLayer];
    1062                 : }
    1063                 : 
    1064                 : /************************************************************************/
    1065                 : /*                            GrowExtents()                             */
    1066                 : /************************************************************************/
    1067                 : 
    1068              26 : void OGRGMLDataSource::GrowExtents( OGREnvelope3D *psGeomBounds, int nCoordDimension )
    1069                 : 
    1070                 : {
    1071              26 :     sBoundingRect.Merge( *psGeomBounds );
    1072              26 :     if (nCoordDimension == 3)
    1073              20 :         bBBOX3D = TRUE;
    1074              26 : }
    1075                 : 
    1076                 : /************************************************************************/
    1077                 : /*                            InsertHeader()                            */
    1078                 : /*                                                                      */
    1079                 : /*      This method is used to update boundedby info for a              */
    1080                 : /*      dataset, and insert schema descriptions depending on            */
    1081                 : /*      selection options in effect.                                    */
    1082                 : /************************************************************************/
    1083                 : 
    1084               9 : void OGRGMLDataSource::InsertHeader()
    1085                 : 
    1086                 : {
    1087                 :     VSILFILE        *fpSchema;
    1088               9 :     int         nSchemaStart = 0;
    1089                 : 
    1090               9 :     if( bFpOutputSingleFile )
    1091               0 :         return;
    1092                 : 
    1093                 : /* -------------------------------------------------------------------- */
    1094                 : /*      Do we want to write the schema within the GML instance doc      */
    1095                 : /*      or to a separate file?  For now we only support external.       */
    1096                 : /* -------------------------------------------------------------------- */
    1097                 :     const char *pszSchemaURI = CSLFetchNameValue(papszCreateOptions,
    1098               9 :                                                  "XSISCHEMAURI");
    1099                 :     const char *pszSchemaOpt = CSLFetchNameValue( papszCreateOptions, 
    1100               9 :                                                   "XSISCHEMA" );
    1101                 : 
    1102               9 :     if( pszSchemaURI != NULL )
    1103               0 :         return;
    1104                 : 
    1105              18 :     if( pszSchemaOpt == NULL || EQUAL(pszSchemaOpt,"EXTERNAL") )
    1106                 :     {
    1107               9 :         const char *pszXSDFilename = CPLResetExtension( pszName, "xsd" );
    1108                 : 
    1109               9 :         fpSchema = VSIFOpenL( pszXSDFilename, "wt" );
    1110               9 :         if( fpSchema == NULL )
    1111                 :         {
    1112                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1113                 :                       "Failed to open file %.500s for schema output.", 
    1114               0 :                       pszXSDFilename );
    1115               0 :             return;
    1116                 :         }
    1117               9 :         PrintLine( fpSchema, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
    1118                 :     }
    1119               0 :     else if( EQUAL(pszSchemaOpt,"INTERNAL") )
    1120                 :     {
    1121               0 :         if (fpOutput == NULL)
    1122               0 :             return;
    1123               0 :         nSchemaStart = (int) VSIFTellL( fpOutput );
    1124               0 :         fpSchema = fpOutput;
    1125                 :     }
    1126                 :     else                                                               
    1127               0 :         return;
    1128                 : 
    1129                 : /* ==================================================================== */
    1130                 : /*      Write the schema section at the end of the file.  Once          */
    1131                 : /*      complete, we will read it back in, and then move the whole      */
    1132                 : /*      file "down" enough to insert the schema at the beginning.       */
    1133                 : /* ==================================================================== */
    1134                 : 
    1135                 : /* -------------------------------------------------------------------- */
    1136                 : /*      Emit the start of the schema section.                           */
    1137                 : /* -------------------------------------------------------------------- */
    1138               9 :     const char *pszTargetNameSpace = "http://ogr.maptools.org/";
    1139               9 :     const char *pszPrefix = "ogr";
    1140                 : 
    1141               9 :     if (IsGML3Output())
    1142                 :     {
    1143                 :         PrintLine( fpSchema,
    1144               4 :                     "<xs:schema ");
    1145                 :         PrintLine( fpSchema,
    1146               4 :                    "    targetNamespace=\"%s\"", pszTargetNameSpace );
    1147                 :         PrintLine( fpSchema,
    1148                 :                    "    xmlns:%s=\"%s\"",
    1149               4 :                     pszPrefix, pszTargetNameSpace );
    1150                 :         PrintLine( fpSchema,
    1151               4 :                    "    xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"");
    1152               4 :         if (IsGML32Output())
    1153                 :         {
    1154                 :             PrintLine( fpSchema,
    1155               1 :                    "    xmlns:gml=\"http://www.opengis.net/gml/3.2\"");
    1156                 :             PrintLine( fpSchema,
    1157               1 :                     "    xmlns:gmlsf=\"http://www.opengis.net/gmlsf/2.0\"");
    1158                 :         }
    1159                 :         else
    1160                 :         {
    1161                 :             PrintLine( fpSchema,
    1162               3 :                     "    xmlns:gml=\"http://www.opengis.net/gml\"");
    1163               3 :             if (!IsGML3DeegreeOutput())
    1164                 :             {
    1165                 :                 PrintLine( fpSchema,
    1166               2 :                         "    xmlns:gmlsf=\"http://www.opengis.net/gmlsf\"");
    1167                 :             }
    1168                 :         }
    1169                 :         PrintLine( fpSchema,
    1170               4 :                    "    elementFormDefault=\"qualified\"");
    1171                 :         PrintLine( fpSchema,
    1172               4 :                    "    version=\"1.0\">");
    1173                 : 
    1174               4 :         if (IsGML32Output())
    1175                 :         {
    1176                 :             PrintLine( fpSchema,
    1177               1 :                     "<xs:annotation>");
    1178                 :             PrintLine( fpSchema,
    1179               1 :                     "  <xs:appinfo source=\"http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd\">");
    1180                 :             PrintLine( fpSchema,
    1181               1 :                     "    <gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>");
    1182                 :             PrintLine( fpSchema,
    1183               1 :                     "  </xs:appinfo>");
    1184                 :             PrintLine( fpSchema,
    1185               1 :                     "</xs:annotation>");
    1186                 : 
    1187                 :             PrintLine( fpSchema,
    1188               1 :                         "<xs:import namespace=\"http://www.opengis.net/gml/3.2\" schemaLocation=\"http://schemas.opengis.net/gml/3.2.1/gml.xsd\"/>" );
    1189                 :             PrintLine( fpSchema,
    1190               1 :                         "<xs:import namespace=\"http://www.opengis.net/gmlsf/2.0\" schemaLocation=\"http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd\"/>" );
    1191                 :         }
    1192                 :         else
    1193                 :         {
    1194               3 :             if (!IsGML3DeegreeOutput())
    1195                 :             {
    1196                 :                 PrintLine( fpSchema,
    1197               2 :                         "<xs:annotation>");
    1198                 :                 PrintLine( fpSchema,
    1199               2 :                         "  <xs:appinfo source=\"http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsfLevels.xsd\">");
    1200                 :                 PrintLine( fpSchema,
    1201               2 :                         "    <gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>");
    1202                 :                 PrintLine( fpSchema,
    1203               2 :                         "    <gmlsf:GMLProfileSchema>http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd</gmlsf:GMLProfileSchema>");
    1204                 :                 PrintLine( fpSchema,
    1205               2 :                         "  </xs:appinfo>");
    1206                 :                 PrintLine( fpSchema,
    1207               2 :                         "</xs:annotation>");
    1208                 :             }
    1209                 : 
    1210                 :             PrintLine( fpSchema,
    1211               3 :                         "<xs:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://schemas.opengis.net/gml/3.1.1/base/gml.xsd\"/>" );
    1212               3 :             if (!IsGML3DeegreeOutput())
    1213                 :             {
    1214                 :                 PrintLine( fpSchema,
    1215               2 :                             "<xs:import namespace=\"http://www.opengis.net/gmlsf\" schemaLocation=\"http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsfLevels.xsd\"/>" );
    1216                 :             }
    1217                 :         }
    1218                 :     }
    1219                 :     else
    1220                 :     {
    1221                 :         PrintLine( fpSchema,
    1222                 :                     "<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\">",
    1223               5 :                     pszTargetNameSpace, pszPrefix, pszTargetNameSpace );
    1224                 : 
    1225                 :         PrintLine( fpSchema,
    1226               5 :                     "<xs:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://schemas.opengis.net/gml/2.1.2/feature.xsd\"/>" );
    1227                 :     }
    1228                 : 
    1229                 : /* -------------------------------------------------------------------- */
    1230                 : /*      Define the FeatureCollection                                    */
    1231                 : /* -------------------------------------------------------------------- */
    1232               9 :     if (IsGML3Output())
    1233                 :     {
    1234               4 :         if (IsGML32Output())
    1235                 :         {
    1236                 :             PrintLine( fpSchema,
    1237                 :                         "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:AbstractGML\"/>",
    1238               1 :                         pszPrefix );
    1239                 :         }
    1240               3 :         else if (IsGML3DeegreeOutput())
    1241                 :         {
    1242                 :             PrintLine( fpSchema,
    1243                 :                         "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_FeatureCollection\"/>",
    1244               1 :                         pszPrefix );
    1245                 :         }
    1246                 :         else
    1247                 :         {
    1248                 :             PrintLine( fpSchema,
    1249                 :                         "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_GML\"/>",
    1250               2 :                         pszPrefix );
    1251                 :         }
    1252                 : 
    1253               4 :         PrintLine( fpSchema, "<xs:complexType name=\"FeatureCollectionType\">");
    1254               4 :         PrintLine( fpSchema, "  <xs:complexContent>" );
    1255               4 :         if (IsGML3DeegreeOutput())
    1256                 :         {
    1257               1 :             PrintLine( fpSchema, "    <xs:extension base=\"gml:AbstractFeatureCollectionType\">" );
    1258               1 :             PrintLine( fpSchema, "      <xs:sequence>" );
    1259               1 :             PrintLine( fpSchema, "        <xs:element name=\"featureMember\" minOccurs=\"0\" maxOccurs=\"unbounded\">" );
    1260                 :         }
    1261                 :         else
    1262                 :         {
    1263               3 :             PrintLine( fpSchema, "    <xs:extension base=\"gml:AbstractFeatureType\">" );
    1264               3 :             PrintLine( fpSchema, "      <xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" );
    1265               3 :             PrintLine( fpSchema, "        <xs:element name=\"featureMember\">" );
    1266                 :         }
    1267               4 :         PrintLine( fpSchema, "          <xs:complexType>" );
    1268               4 :         if (IsGML32Output())
    1269                 :         {
    1270               1 :             PrintLine( fpSchema, "            <xs:complexContent>" );
    1271               1 :             PrintLine( fpSchema, "              <xs:extension base=\"gml:AbstractFeatureMemberType\">" );
    1272               1 :             PrintLine( fpSchema, "                <xs:sequence>" );
    1273               1 :             PrintLine( fpSchema, "                  <xs:element ref=\"gml:AbstractFeature\"/>" );
    1274               1 :             PrintLine( fpSchema, "                </xs:sequence>" );
    1275               1 :             PrintLine( fpSchema, "              </xs:extension>" );
    1276               1 :             PrintLine( fpSchema, "            </xs:complexContent>" );
    1277                 :         }
    1278                 :         else
    1279                 :         {
    1280               3 :             PrintLine( fpSchema, "            <xs:sequence>" );
    1281               3 :             PrintLine( fpSchema, "              <xs:element ref=\"gml:_Feature\"/>" );
    1282               3 :             PrintLine( fpSchema, "            </xs:sequence>" );
    1283                 :         }
    1284               4 :         PrintLine( fpSchema, "          </xs:complexType>" );
    1285               4 :         PrintLine( fpSchema, "        </xs:element>" );
    1286               4 :         PrintLine( fpSchema, "      </xs:sequence>" );
    1287               4 :         PrintLine( fpSchema, "    </xs:extension>" );
    1288               4 :         PrintLine( fpSchema, "  </xs:complexContent>" );
    1289               4 :         PrintLine( fpSchema, "</xs:complexType>" );
    1290                 :     }
    1291                 :     else
    1292                 :     {
    1293                 :         PrintLine( fpSchema,
    1294                 :                     "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_FeatureCollection\"/>",
    1295               5 :                     pszPrefix );
    1296                 : 
    1297               5 :         PrintLine( fpSchema, "<xs:complexType name=\"FeatureCollectionType\">");
    1298               5 :         PrintLine( fpSchema, "  <xs:complexContent>" );
    1299               5 :         PrintLine( fpSchema, "    <xs:extension base=\"gml:AbstractFeatureCollectionType\">" );
    1300               5 :         PrintLine( fpSchema, "      <xs:attribute name=\"lockId\" type=\"xs:string\" use=\"optional\"/>" );
    1301               5 :         PrintLine( fpSchema, "      <xs:attribute name=\"scope\" type=\"xs:string\" use=\"optional\"/>" );
    1302               5 :         PrintLine( fpSchema, "    </xs:extension>" );
    1303               5 :         PrintLine( fpSchema, "  </xs:complexContent>" );
    1304               5 :         PrintLine( fpSchema, "</xs:complexType>" );
    1305                 :     }
    1306                 : 
    1307                 : /* ==================================================================== */
    1308                 : /*      Define the schema for each layer.                               */
    1309                 : /* ==================================================================== */
    1310                 :     int iLayer;
    1311                 : 
    1312              18 :     for( iLayer = 0; iLayer < GetLayerCount(); iLayer++ )
    1313                 :     {
    1314               9 :         OGRFeatureDefn *poFDefn = GetLayer(iLayer)->GetLayerDefn();
    1315                 :         
    1316                 : /* -------------------------------------------------------------------- */
    1317                 : /*      Emit initial stuff for a feature type.                          */
    1318                 : /* -------------------------------------------------------------------- */
    1319               9 :         if (IsGML32Output())
    1320                 :         {
    1321                 :             PrintLine(
    1322                 :                 fpSchema,
    1323                 :                 "<xs:element name=\"%s\" type=\"%s:%s_Type\" substitutionGroup=\"gml:AbstractFeature\"/>",
    1324               1 :                 poFDefn->GetName(), pszPrefix, poFDefn->GetName() );
    1325                 :         }
    1326                 :         else
    1327                 :         {
    1328                 :             PrintLine(
    1329                 :                 fpSchema,
    1330                 :                 "<xs:element name=\"%s\" type=\"%s:%s_Type\" substitutionGroup=\"gml:_Feature\"/>",
    1331               8 :                 poFDefn->GetName(), pszPrefix, poFDefn->GetName() );
    1332                 :         }
    1333                 : 
    1334               9 :         PrintLine( fpSchema, "<xs:complexType name=\"%s_Type\">", poFDefn->GetName());
    1335               9 :         PrintLine( fpSchema, "  <xs:complexContent>");
    1336               9 :         PrintLine( fpSchema, "    <xs:extension base=\"gml:AbstractFeatureType\">");
    1337               9 :         PrintLine( fpSchema, "      <xs:sequence>");
    1338                 : 
    1339                 : /* -------------------------------------------------------------------- */
    1340                 : /*      Define the geometry attribute.                                  */
    1341                 : /* -------------------------------------------------------------------- */
    1342               9 :         const char* pszGeometryTypeName = "GeometryPropertyType";
    1343               9 :         switch(wkbFlatten(poFDefn->GetGeomType()))
    1344                 :         {
    1345                 :             case wkbPoint:
    1346               0 :                 pszGeometryTypeName = "PointPropertyType";
    1347               0 :                 break;
    1348                 :             case wkbLineString:
    1349               0 :                 if (IsGML3Output())
    1350               0 :                     pszGeometryTypeName = "CurvePropertyType";
    1351                 :                 else
    1352               0 :                     pszGeometryTypeName = "LineStringPropertyType";
    1353               0 :                 break;
    1354                 :             case wkbPolygon:
    1355               2 :                 if (IsGML3Output())
    1356               1 :                     pszGeometryTypeName = "SurfacePropertyType";
    1357                 :                 else
    1358               1 :                     pszGeometryTypeName = "PolygonPropertyType";
    1359               2 :                 break;
    1360                 :             case wkbMultiPoint:
    1361               0 :                 pszGeometryTypeName = "MultiPointPropertyType";
    1362               0 :                 break;
    1363                 :             case wkbMultiLineString:
    1364               0 :                 if (IsGML3Output())
    1365               0 :                     pszGeometryTypeName = "MutliCurvePropertyType";
    1366                 :                 else
    1367               0 :                     pszGeometryTypeName = "MultiLineStringPropertyType";
    1368               0 :                 break;
    1369                 :             case wkbMultiPolygon:
    1370               0 :                 if (IsGML3Output())
    1371               0 :                     pszGeometryTypeName = "MultiSurfacePropertyType";
    1372                 :                 else
    1373               0 :                     pszGeometryTypeName = "MultiPolygonPropertyType";
    1374               0 :                 break;
    1375                 :             case wkbGeometryCollection:
    1376               0 :                 pszGeometryTypeName = "MultiGeometryPropertyType";
    1377                 :                 break;
    1378                 :             default:
    1379                 :                 break;
    1380                 :         }
    1381                 : 
    1382               9 :         if (poFDefn->GetGeomType() != wkbNone)
    1383                 :         {
    1384                 :             PrintLine( fpSchema,
    1385               8 :                 "        <xs:element name=\"geometryProperty\" type=\"gml:%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\"/>", pszGeometryTypeName );
    1386                 :         }
    1387                 :             
    1388                 : /* -------------------------------------------------------------------- */
    1389                 : /*      Emit each of the attributes.                                    */
    1390                 : /* -------------------------------------------------------------------- */
    1391              27 :         for( int iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
    1392                 :         {
    1393              18 :             OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(iField);
    1394                 : 
    1395              18 :             if( poFieldDefn->GetType() == OFTInteger )
    1396                 :             {
    1397                 :                 int nWidth;
    1398                 : 
    1399               2 :                 if( poFieldDefn->GetWidth() > 0 )
    1400               2 :                     nWidth = poFieldDefn->GetWidth();
    1401                 :                 else
    1402               0 :                     nWidth = 16;
    1403                 : 
    1404               2 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">", poFieldDefn->GetNameRef());
    1405               2 :                 PrintLine( fpSchema, "          <xs:simpleType>");
    1406               2 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:integer\">");
    1407               2 :                 PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
    1408               2 :                 PrintLine( fpSchema, "            </xs:restriction>");
    1409               2 :                 PrintLine( fpSchema, "          </xs:simpleType>");
    1410               2 :                 PrintLine( fpSchema, "        </xs:element>");
    1411                 :             }
    1412              16 :             else if( poFieldDefn->GetType() == OFTReal )
    1413                 :             {
    1414                 :                 int nWidth, nDecimals;
    1415                 : 
    1416               6 :                 nWidth = poFieldDefn->GetWidth();
    1417               6 :                 nDecimals = poFieldDefn->GetPrecision();
    1418                 : 
    1419               6 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
    1420               6 :                 PrintLine( fpSchema, "          <xs:simpleType>");
    1421               6 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:decimal\">");
    1422               6 :                 if (nWidth > 0)
    1423                 :                 {
    1424               5 :                     PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
    1425               5 :                     PrintLine( fpSchema, "              <xs:fractionDigits value=\"%d\"/>", nDecimals);
    1426                 :                 }
    1427               6 :                 PrintLine( fpSchema, "            </xs:restriction>");
    1428               6 :                 PrintLine( fpSchema, "          </xs:simpleType>");
    1429               6 :                 PrintLine( fpSchema, "        </xs:element>");
    1430                 :             }
    1431              10 :             else if( poFieldDefn->GetType() == OFTString )
    1432                 :             {
    1433               9 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
    1434               9 :                 PrintLine( fpSchema, "          <xs:simpleType>");
    1435               9 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:string\">");
    1436               9 :                 if( poFieldDefn->GetWidth() != 0 )
    1437                 :                 {
    1438               4 :                     PrintLine( fpSchema, "              <xs:maxLength value=\"%d\"/>", poFieldDefn->GetWidth());
    1439                 :                 }
    1440               9 :                 PrintLine( fpSchema, "            </xs:restriction>");
    1441               9 :                 PrintLine( fpSchema, "          </xs:simpleType>");
    1442               9 :                 PrintLine( fpSchema, "        </xs:element>");
    1443                 :             }
    1444               1 :             else if( poFieldDefn->GetType() == OFTDate || poFieldDefn->GetType() == OFTDateTime )
    1445                 :             {
    1446               1 :                 PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
    1447               1 :                 PrintLine( fpSchema, "          <xs:simpleType>");
    1448               1 :                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:string\">");
    1449               1 :                 PrintLine( fpSchema, "            </xs:restriction>");
    1450               1 :                 PrintLine( fpSchema, "          </xs:simpleType>");
    1451               1 :                 PrintLine( fpSchema, "        </xs:element>");
    1452                 :             }
    1453                 :             else
    1454                 :             {
    1455                 :                 /* TODO */
    1456                 :             }
    1457                 :         } /* next field */
    1458                 : 
    1459                 : /* -------------------------------------------------------------------- */
    1460                 : /*      Finish off feature type.                                        */
    1461                 : /* -------------------------------------------------------------------- */
    1462               9 :         PrintLine( fpSchema, "      </xs:sequence>");
    1463               9 :         PrintLine( fpSchema, "    </xs:extension>");
    1464               9 :         PrintLine( fpSchema, "  </xs:complexContent>");
    1465               9 :         PrintLine( fpSchema, "</xs:complexType>" );
    1466                 :     } /* next layer */
    1467                 : 
    1468               9 :     PrintLine( fpSchema, "</xs:schema>" );
    1469                 : 
    1470                 : /* ==================================================================== */
    1471                 : /*      Move schema to the start of the file.                           */
    1472                 : /* ==================================================================== */
    1473               9 :     if( fpSchema == fpOutput )
    1474                 :     {
    1475                 : /* -------------------------------------------------------------------- */
    1476                 : /*      Read the schema into memory.                                    */
    1477                 : /* -------------------------------------------------------------------- */
    1478               0 :         int nSchemaSize = (int) VSIFTellL( fpOutput ) - nSchemaStart;
    1479               0 :         char *pszSchema = (char *) CPLMalloc(nSchemaSize+1);
    1480                 :     
    1481               0 :         VSIFSeekL( fpOutput, nSchemaStart, SEEK_SET );
    1482                 : 
    1483               0 :         VSIFReadL( pszSchema, 1, nSchemaSize, fpOutput );
    1484               0 :         pszSchema[nSchemaSize] = '\0';
    1485                 :     
    1486                 : /* -------------------------------------------------------------------- */
    1487                 : /*      Move file data down by "schema size" bytes from after <?xml>    */
    1488                 : /*      header so we have room insert the schema.  Move in pretty       */
    1489                 : /*      big chunks.                                                     */
    1490                 : /* -------------------------------------------------------------------- */
    1491               0 :         int nChunkSize = MIN(nSchemaStart-nSchemaInsertLocation,250000);
    1492               0 :         char *pszChunk = (char *) CPLMalloc(nChunkSize);
    1493               0 :         int nEndOfUnmovedData = nSchemaStart;
    1494                 : 
    1495               0 :         for( nEndOfUnmovedData = nSchemaStart;
    1496                 :              nEndOfUnmovedData > nSchemaInsertLocation; )
    1497                 :         {
    1498                 :             int nBytesToMove = 
    1499               0 :                 MIN(nChunkSize, nEndOfUnmovedData - nSchemaInsertLocation );
    1500                 : 
    1501               0 :             VSIFSeekL( fpOutput, nEndOfUnmovedData - nBytesToMove, SEEK_SET );
    1502               0 :             VSIFReadL( pszChunk, 1, nBytesToMove, fpOutput );
    1503                 :             VSIFSeekL( fpOutput, nEndOfUnmovedData - nBytesToMove + nSchemaSize, 
    1504               0 :                       SEEK_SET );
    1505               0 :             VSIFWriteL( pszChunk, 1, nBytesToMove, fpOutput );
    1506                 :         
    1507               0 :             nEndOfUnmovedData -= nBytesToMove;
    1508                 :         }
    1509                 : 
    1510               0 :         CPLFree( pszChunk );
    1511                 : 
    1512                 : /* -------------------------------------------------------------------- */
    1513                 : /*      Write the schema in the opened slot.                            */
    1514                 : /* -------------------------------------------------------------------- */
    1515               0 :         VSIFSeekL( fpOutput, nSchemaInsertLocation, SEEK_SET );
    1516               0 :         VSIFWriteL( pszSchema, 1, nSchemaSize, fpOutput );
    1517                 : 
    1518               0 :         VSIFSeekL( fpOutput, 0, SEEK_END );
    1519                 : 
    1520               0 :         nBoundedByLocation += nSchemaSize;
    1521                 : 
    1522               0 :         CPLFree(pszSchema);
    1523                 :     }
    1524                 : /* -------------------------------------------------------------------- */
    1525                 : /*      Close external schema files.                                    */
    1526                 : /* -------------------------------------------------------------------- */
    1527                 :     else
    1528               9 :         VSIFCloseL( fpSchema );
    1529                 : }
    1530                 : 
    1531                 : 
    1532                 : /************************************************************************/
    1533                 : /*                            PrintLine()                               */
    1534                 : /************************************************************************/
    1535                 : 
    1536             762 : void OGRGMLDataSource::PrintLine(VSILFILE* fp, const char *fmt, ...)
    1537                 : {
    1538             762 :     CPLString osWork;
    1539                 :     va_list args;
    1540                 : 
    1541             762 :     va_start( args, fmt );
    1542             762 :     osWork.vPrintf( fmt, args );
    1543             762 :     va_end( args );
    1544                 : 
    1545                 : #ifdef WIN32
    1546                 :     const char* pszEOL = "\r\n";
    1547                 : #else
    1548             762 :     const char* pszEOL = "\n";
    1549                 : #endif
    1550                 : 
    1551             762 :     VSIFPrintfL(fp, "%s%s", osWork.c_str(), pszEOL);
    1552             762 : }

Generated by: LCOV version 1.7