LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gml - ogrgmldatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 233 173 74.2 %
Date: 2010-01-09 Functions: 11 9 81.8 %

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

Generated by: LCOV version 1.7