LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapedatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 370 290 78.4 %
Date: 2011-12-18 Functions: 15 12 80.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrshapedatasource.cpp 23526 2011-12-11 12:16:27Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRShapeDataSource class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
      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 "ogrshape.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : 
      34                 : #define MAX_SIMULTANEOUSLY_OPENED_LAYERS    100
      35                 : 
      36                 : CPL_CVSID("$Id: ogrshapedatasource.cpp 23526 2011-12-11 12:16:27Z rouault $");
      37                 : 
      38                 : /************************************************************************/
      39                 : /*                         OGRShapeDataSource()                         */
      40                 : /************************************************************************/
      41                 : 
      42            1202 : OGRShapeDataSource::OGRShapeDataSource()
      43                 : 
      44                 : {
      45            1202 :     pszName = NULL;
      46            1202 :     papoLayers = NULL;
      47            1202 :     nLayers = 0;
      48            1202 :     bSingleFileDataSource = FALSE;
      49                 : 
      50            1202 :     poMRULayer = NULL;
      51            1202 :     poLRULayer = NULL;
      52            1202 :     nMRUListSize = 0;
      53            1202 : }
      54                 : 
      55                 : /************************************************************************/
      56                 : /*                        ~OGRShapeDataSource()                         */
      57                 : /************************************************************************/
      58                 : 
      59            1202 : OGRShapeDataSource::~OGRShapeDataSource()
      60                 : 
      61                 : {
      62            1202 :     CPLFree( pszName );
      63                 : 
      64            5452 :     for( int i = 0; i < nLayers; i++ )
      65                 :     {
      66            4250 :         CPLAssert( NULL != papoLayers[i] );
      67                 : 
      68            4250 :         delete papoLayers[i];
      69                 :     }
      70                 : 
      71            1202 :     CPLAssert( poMRULayer == NULL );
      72            1202 :     CPLAssert( poLRULayer == NULL );
      73            1202 :     CPLAssert( nMRUListSize == 0 );
      74                 :     
      75            1202 :     CPLFree( papoLayers );
      76            1202 : }
      77                 : 
      78                 : /************************************************************************/
      79                 : /*                                Open()                                */
      80                 : /************************************************************************/
      81                 : 
      82            1202 : int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
      83                 :                               int bTestOpen, int bForceSingleFileDataSource )
      84                 : 
      85                 : {
      86                 :     VSIStatBufL  stat;
      87                 :     
      88            1202 :     CPLAssert( nLayers == 0 );
      89                 :     
      90            1202 :     pszName = CPLStrdup( pszNewName );
      91                 : 
      92            1202 :     bDSUpdate = bUpdate;
      93                 : 
      94            1202 :     bSingleFileDataSource = bForceSingleFileDataSource;
      95                 : 
      96                 : /* -------------------------------------------------------------------- */
      97                 : /*      If  bSingleFileDataSource is TRUE we don't try to do anything else.     */
      98                 : /*      This is only utilized when the OGRShapeDriver::Create()         */
      99                 : /*      method wants to create a stub OGRShapeDataSource for a          */
     100                 : /*      single shapefile.  The driver will take care of creating the    */
     101                 : /*      file by calling CreateLayer().                                  */
     102                 : /* -------------------------------------------------------------------- */
     103            1202 :     if( bSingleFileDataSource )
     104              88 :         return TRUE;
     105                 :     
     106                 : /* -------------------------------------------------------------------- */
     107                 : /*      Is the given path a directory or a regular file?                */
     108                 : /* -------------------------------------------------------------------- */
     109            1114 :     if( VSIStatExL( pszNewName, &stat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 
     110                 :         || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
     111                 :     {
     112             172 :         if( !bTestOpen )
     113                 :             CPLError( CE_Failure, CPLE_AppDefined,
     114                 :                    "%s is neither a file or directory, Shape access failed.\n",
     115               0 :                       pszNewName );
     116                 : 
     117             172 :         return FALSE;
     118                 :     }
     119                 :     
     120                 : /* -------------------------------------------------------------------- */
     121                 : /*      Build a list of filenames we figure are Shape files.            */
     122                 : /* -------------------------------------------------------------------- */
     123             942 :     if( VSI_ISREG(stat.st_mode) )
     124                 :     {
     125             812 :         if( !OpenFile( pszNewName, bUpdate, bTestOpen ) )
     126                 :         {
     127             489 :             if( !bTestOpen )
     128                 :                 CPLError( CE_Failure, CPLE_OpenFailed,
     129                 :                           "Failed to open shapefile %s.\n"
     130                 :                           "It may be corrupt or read-only file accessed in update mode.\n",
     131               0 :                           pszNewName );
     132                 : 
     133             489 :             return FALSE;
     134                 :         }
     135                 : 
     136             323 :         bSingleFileDataSource = TRUE;
     137                 : 
     138             323 :         return TRUE;
     139                 :     }
     140                 :     else
     141                 :     {
     142             130 :         char      **papszCandidates = CPLReadDir( pszNewName );
     143             130 :         int       iCan, nCandidateCount = CSLCount( papszCandidates );
     144             130 :         int       bMightBeOldCoverage = FALSE;
     145                 : 
     146           11492 :         for( iCan = 0; iCan < nCandidateCount; iCan++ )
     147                 :         {
     148                 :             char        *pszFilename;
     149           11362 :             const char  *pszCandidate = papszCandidates[iCan];
     150                 : 
     151           11362 :             if( EQUAL(pszCandidate,"ARC") )
     152               0 :                 bMightBeOldCoverage = TRUE;
     153                 : 
     154           11362 :             if( strlen(pszCandidate) < 4
     155                 :                 || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".shp") )
     156            8125 :                 continue;
     157                 : 
     158                 :             pszFilename =
     159            3237 :                 CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
     160                 : 
     161            3237 :             if( !OpenFile( pszFilename, bUpdate, bTestOpen )
     162                 :                 && !bTestOpen )
     163                 :             {
     164                 :                 CPLError( CE_Failure, CPLE_OpenFailed,
     165                 :                           "Failed to open shapefile %s.\n"
     166                 :                           "It may be corrupt or read-only file accessed in update mode.\n",
     167               0 :                           pszFilename );
     168               0 :                 CPLFree( pszFilename );
     169               0 :                 return FALSE;
     170                 :             }
     171                 :             
     172            3237 :             CPLFree( pszFilename );
     173                 :         }
     174                 : 
     175                 :         // Try and .dbf files without apparent associated shapefiles. 
     176           11492 :         for( iCan = 0; iCan < nCandidateCount; iCan++ )
     177                 :         {
     178                 :             char        *pszFilename;
     179           11362 :             const char  *pszCandidate = papszCandidates[iCan];
     180                 :             const char  *pszLayerName;
     181           11362 :             int         iLayer, bGotAlready = FALSE;
     182                 : 
     183                 :             // We don't consume .dbf files in a directory that looks like
     184                 :             // an old style Arc/Info (for PC?) that unless we found at least
     185                 :             // some shapefiles.  See Bug 493. 
     186           11362 :             if( bMightBeOldCoverage && nLayers == 0 )
     187               0 :                 continue;
     188                 : 
     189           11362 :             if( strlen(pszCandidate) < 4
     190                 :                 || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".dbf") )
     191            8131 :                 continue;
     192                 : 
     193            3231 :             pszLayerName = CPLGetBasename(pszCandidate);
     194         1267703 :             for( iLayer = 0; iLayer < nLayers; iLayer++ )
     195                 :             {
     196         1264472 :                 if( EQUAL(pszLayerName,
     197                 :                           GetLayer(iLayer)->GetLayerDefn()->GetName()) )
     198            3216 :                     bGotAlready = TRUE;
     199                 :             }
     200                 :             
     201            3231 :             if( bGotAlready )
     202            3216 :                 continue;
     203                 : 
     204                 :             // We don't want to access .dbf files with an associated .tab
     205                 :             // file, or it will never get recognised as a mapinfo dataset.
     206              15 :             int  iCan2, bFoundTAB = FALSE;
     207            3420 :             for( iCan2 = 0; iCan2 < nCandidateCount; iCan2++ )
     208                 :             {
     209            3405 :                 const char *pszCandidate2 = papszCandidates[iCan2];
     210                 : 
     211            3405 :                 if( EQUALN(pszCandidate2,pszLayerName,strlen(pszLayerName))
     212                 :                     && EQUAL(pszCandidate2 + strlen(pszLayerName), ".tab") )
     213               0 :                     bFoundTAB = TRUE;
     214                 :             }
     215                 : 
     216              15 :             if( bFoundTAB )
     217               0 :                 continue;
     218                 :             
     219                 :             pszFilename =
     220              15 :                 CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
     221                 : 
     222              15 :             if( !OpenFile( pszFilename, bUpdate, bTestOpen )
     223                 :                 && !bTestOpen )
     224                 :             {
     225                 :                 CPLError( CE_Failure, CPLE_OpenFailed,
     226                 :                           "Failed to open dbf file %s.\n"
     227                 :                           "It may be corrupt or read-only file accessed in update mode.\n",
     228               0 :                           pszFilename );
     229               0 :                 CPLFree( pszFilename );
     230               0 :                 return FALSE;
     231                 :             }
     232                 :             
     233              15 :             CPLFree( pszFilename );
     234                 :         }
     235                 : 
     236             130 :         CSLDestroy( papszCandidates );
     237                 :         
     238             130 :         if( !bTestOpen && nLayers == 0 && !bUpdate )
     239                 :         {
     240                 :             CPLError( CE_Failure, CPLE_OpenFailed,
     241                 :                       "No Shapefiles found in directory %s\n",
     242               0 :                       pszNewName );
     243                 :         }
     244                 :     }
     245                 : 
     246             130 :     return nLayers > 0 || bUpdate;
     247                 : }
     248                 : 
     249                 : /************************************************************************/
     250                 : /*                              OpenFile()                              */
     251                 : /************************************************************************/
     252                 : 
     253            4064 : int OGRShapeDataSource::OpenFile( const char *pszNewName, int bUpdate,
     254                 :                                   int bTestOpen )
     255                 : 
     256                 : {
     257                 :     SHPHandle   hSHP;
     258                 :     DBFHandle   hDBF;
     259            4064 :     const char *pszExtension = CPLGetExtension( pszNewName );
     260                 : 
     261                 :     (void) bTestOpen;
     262                 : 
     263            4064 :     if( !EQUAL(pszExtension,"shp") && !EQUAL(pszExtension,"shx")
     264                 :         && !EQUAL(pszExtension,"dbf") )
     265             489 :         return FALSE;
     266                 : 
     267                 : /* -------------------------------------------------------------------- */
     268                 : /*      SHPOpen() should include better (CPL based) error reporting,    */
     269                 : /*      and we should be trying to distinquish at this point whether    */
     270                 : /*      failure is a result of trying to open a non-shapefile, or       */
     271                 : /*      whether it was a shapefile and we want to report the error      */
     272                 : /*      up.                                                             */
     273                 : /*                                                                      */
     274                 : /*      Care is taken to suppress the error and only reissue it if      */
     275                 : /*      we think it is appropriate.                                     */
     276                 : /* -------------------------------------------------------------------- */
     277            3575 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     278            3575 :     if( bUpdate )
     279            1693 :         hSHP = SHPOpen( pszNewName, "r+" );
     280                 :     else
     281            1882 :         hSHP = SHPOpen( pszNewName, "r" );
     282            3575 :     CPLPopErrorHandler();
     283                 : 
     284            3575 :     if( hSHP == NULL 
     285                 :         && (!EQUAL(CPLGetExtension(pszNewName),"dbf") 
     286                 :             || strstr(CPLGetLastErrorMsg(),".shp") == NULL) )
     287                 :     {
     288               0 :         CPLString osMsg = CPLGetLastErrorMsg();
     289                 : 
     290               0 :         CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() );
     291                 : 
     292               0 :         return FALSE;
     293                 :     }
     294            3575 :     CPLErrorReset();
     295                 :     
     296                 : /* -------------------------------------------------------------------- */
     297                 : /*      Open the .dbf file, if it exists.  To open a dbf file, the      */
     298                 : /*      filename has to either refer to a successfully opened shp       */
     299                 : /*      file or has to refer to the actual .dbf file.                   */
     300                 : /* -------------------------------------------------------------------- */
     301            3575 :     if( hSHP != NULL || EQUAL(CPLGetExtension(pszNewName),"dbf") )
     302                 :     {
     303            3575 :         if( bUpdate )
     304                 :         {
     305            1693 :             hDBF = DBFOpen( pszNewName, "r+" );
     306            1693 :             if( hSHP != NULL && hDBF == NULL )
     307                 :             {
     308                 :                 VSIStatBufL sStat;
     309               3 :                 const char* pszDBFName = CPLResetExtension(pszNewName, "dbf");
     310               3 :                 VSILFILE* fp = NULL;
     311               3 :                 if( VSIStatExL( pszDBFName, &sStat, VSI_STAT_EXISTS_FLAG) == 0 )
     312                 :                 {
     313               0 :                     fp = VSIFOpenL(pszDBFName, "r+");
     314               0 :                     if (fp == NULL)
     315                 :                     {
     316                 :                         CPLError( CE_Failure, CPLE_OpenFailed,
     317                 :                                 "%s exists, but cannot be opened in update mode",
     318               0 :                                 pszDBFName );
     319               0 :                         return FALSE;
     320                 :                     }
     321                 :                 }
     322                 :                 else
     323                 :                 {
     324               3 :                     pszDBFName = CPLResetExtension(pszNewName, "DBF");
     325               3 :                     if( VSIStatExL( pszDBFName, &sStat, VSI_STAT_EXISTS_FLAG) == 0 )
     326                 :                     {
     327               0 :                         fp = VSIFOpenL(pszDBFName, "r+");
     328               0 :                         if (fp == NULL)
     329                 :                         {
     330                 :                             CPLError( CE_Failure, CPLE_OpenFailed,
     331                 :                                     "%s exists, but cannot be opened in update mode",
     332               0 :                                     pszDBFName );
     333               0 :                             return FALSE;
     334                 :                         }
     335                 :                     }
     336                 :                 }
     337               3 :                 if (fp != NULL)
     338               0 :                     VSIFCloseL(fp);
     339                 :             }
     340                 :         }
     341                 :         else
     342            1882 :             hDBF = DBFOpen( pszNewName, "r" );
     343                 :     }
     344                 :     else
     345               0 :         hDBF = NULL;
     346                 :         
     347            3575 :     if( hDBF == NULL && hSHP == NULL )
     348               0 :         return FALSE;
     349                 : 
     350                 : /* -------------------------------------------------------------------- */
     351                 : /*      Create the layer object.                                        */
     352                 : /* -------------------------------------------------------------------- */
     353                 :     OGRShapeLayer       *poLayer;
     354                 : 
     355                 :     poLayer = new OGRShapeLayer( this, pszNewName, hSHP, hDBF, NULL, FALSE, bUpdate,
     356            3575 :                                  wkbNone );
     357                 : 
     358                 : /* -------------------------------------------------------------------- */
     359                 : /*      Add layer to data source layer list.                            */
     360                 : /* -------------------------------------------------------------------- */
     361            3575 :     AddLayer(poLayer);
     362                 : 
     363            3575 :     return TRUE;
     364                 : }
     365                 : 
     366                 : 
     367                 : /************************************************************************/
     368                 : /*                             AddLayer()                               */
     369                 : /************************************************************************/
     370                 : 
     371            4758 : void OGRShapeDataSource::AddLayer(OGRShapeLayer* poLayer)
     372                 : {
     373                 :     papoLayers = (OGRShapeLayer **)
     374            4758 :         CPLRealloc( papoLayers,  sizeof(OGRShapeLayer *) * (nLayers+1) );
     375            4758 :     papoLayers[nLayers++] = poLayer;
     376                 : 
     377                 :     /* If we reach the limit, then register all the already opened layers */
     378                 :     /* Technically this code would not be necessary if there was not the */
     379                 :     /* following initial test in SetLastUsedLayer() : */
     380                 :     /*      if (nLayers < MAX_SIMULTANEOUSLY_OPENED_LAYERS) */
     381                 :     /*         return; */
     382            4758 :     if (nLayers == MAX_SIMULTANEOUSLY_OPENED_LAYERS && nMRUListSize == 0)
     383                 :     {
     384             707 :         for(int i=0;i<nLayers;i++)
     385             700 :             SetLastUsedLayer(papoLayers[i]);
     386                 :     }
     387            4758 : }
     388                 : 
     389                 : /************************************************************************/
     390                 : /*                            CreateLayer()                             */
     391                 : /************************************************************************/
     392                 : 
     393                 : OGRLayer *
     394            1184 : OGRShapeDataSource::CreateLayer( const char * pszLayerName,
     395                 :                                  OGRSpatialReference *poSRS,
     396                 :                                  OGRwkbGeometryType eType,
     397                 :                                  char ** papszOptions )
     398                 : 
     399                 : {
     400                 :     SHPHandle   hSHP;
     401                 :     DBFHandle   hDBF;
     402                 :     int         nShapeType;
     403                 :     int         iLayer;
     404                 : 
     405                 : /* -------------------------------------------------------------------- */
     406                 : /*      Check that the layer doesn't already exist.                     */
     407                 : /* -------------------------------------------------------------------- */
     408          252263 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     409                 :     {
     410          251080 :         OGRLayer        *poLayer = papoLayers[iLayer];
     411                 : 
     412          502160 :         if( poLayer != NULL 
     413          251080 :             && EQUAL(poLayer->GetLayerDefn()->GetName(),pszLayerName) )
     414                 :         {
     415                 :             CPLError( CE_Failure, CPLE_AppDefined, "Layer '%s' already exists",
     416               1 :                       pszLayerName);
     417               1 :             return NULL;
     418                 :         }
     419                 :     }
     420                 : 
     421                 : /* -------------------------------------------------------------------- */
     422                 : /*      Verify we are in update mode.                                   */
     423                 : /* -------------------------------------------------------------------- */
     424            1183 :     if( !bDSUpdate )
     425                 :     {
     426                 :         CPLError( CE_Failure, CPLE_NoWriteAccess,
     427                 :                   "Data source %s opened read-only.\n"
     428                 :                   "New layer %s cannot be created.\n",
     429               0 :                   pszName, pszLayerName );
     430                 : 
     431               0 :         return NULL;
     432                 :     }
     433                 : 
     434                 : /* -------------------------------------------------------------------- */
     435                 : /*      Figure out what type of layer we need.                          */
     436                 : /* -------------------------------------------------------------------- */
     437            2272 :     if( eType == wkbUnknown || eType == wkbLineString )
     438            1089 :         nShapeType = SHPT_ARC;
     439              94 :     else if( eType == wkbPoint )
     440               2 :         nShapeType = SHPT_POINT;
     441              92 :     else if( eType == wkbPolygon )
     442              67 :         nShapeType = SHPT_POLYGON;
     443              25 :     else if( eType == wkbMultiPoint )
     444               2 :         nShapeType = SHPT_MULTIPOINT;
     445              23 :     else if( eType == wkbPoint25D )
     446               1 :         nShapeType = SHPT_POINTZ;
     447              22 :     else if( eType == wkbLineString25D )
     448               4 :         nShapeType = SHPT_ARCZ;
     449              18 :     else if( eType == wkbMultiLineString )
     450               2 :         nShapeType = SHPT_ARC;
     451              16 :     else if( eType == wkbMultiLineString25D )
     452               1 :         nShapeType = SHPT_ARCZ;
     453              15 :     else if( eType == wkbPolygon25D )
     454               5 :         nShapeType = SHPT_POLYGONZ;
     455              10 :     else if( eType == wkbMultiPolygon )
     456               5 :         nShapeType = SHPT_POLYGON;
     457               5 :     else if( eType == wkbMultiPolygon25D )
     458               1 :         nShapeType = SHPT_POLYGONZ;
     459               4 :     else if( eType == wkbMultiPoint25D )
     460               1 :         nShapeType = SHPT_MULTIPOINTZ;
     461               3 :     else if( eType == wkbNone )
     462               3 :         nShapeType = SHPT_NULL;
     463                 :     else
     464               0 :         nShapeType = -1;
     465                 : 
     466                 : /* -------------------------------------------------------------------- */
     467                 : /*      Has the application overridden this with a special creation     */
     468                 : /*      option?                                                         */
     469                 : /* -------------------------------------------------------------------- */
     470            1183 :     const char *pszOverride = CSLFetchNameValue( papszOptions, "SHPT" );
     471                 : 
     472            1183 :     if( pszOverride == NULL )
     473                 :         /* ignore */;
     474               2 :     else if( EQUAL(pszOverride,"POINT") )
     475                 :     {
     476               0 :         nShapeType = SHPT_POINT;
     477               0 :         eType = wkbPoint;
     478                 :     }
     479               2 :     else if( EQUAL(pszOverride,"ARC") )
     480                 :     {
     481               0 :         nShapeType = SHPT_ARC;
     482               0 :         eType = wkbLineString;
     483                 :     }
     484               2 :     else if( EQUAL(pszOverride,"POLYGON") )
     485                 :     {
     486               0 :         nShapeType = SHPT_POLYGON;
     487               0 :         eType = wkbPolygon;
     488                 :     }
     489               2 :     else if( EQUAL(pszOverride,"MULTIPOINT") )
     490                 :     {
     491               0 :         nShapeType = SHPT_MULTIPOINT;
     492               0 :         eType = wkbMultiPoint;
     493                 :     }
     494               2 :     else if( EQUAL(pszOverride,"POINTZ") )
     495                 :     {
     496               0 :         nShapeType = SHPT_POINTZ;
     497               0 :         eType = wkbPoint25D;
     498                 :     }
     499               2 :     else if( EQUAL(pszOverride,"ARCZ") )
     500                 :     {
     501               0 :         nShapeType = SHPT_ARCZ;
     502               0 :         eType = wkbLineString25D;
     503                 :     }
     504               2 :     else if( EQUAL(pszOverride,"POLYGONZ") )
     505                 :     {
     506               2 :         nShapeType = SHPT_POLYGONZ;
     507               2 :         eType = wkbPolygon25D;
     508                 :     }
     509               0 :     else if( EQUAL(pszOverride,"MULTIPOINTZ") )
     510                 :     {
     511               0 :         nShapeType = SHPT_MULTIPOINTZ;
     512               0 :         eType = wkbMultiPoint25D;
     513                 :     }
     514               0 :     else if( EQUAL(pszOverride,"NONE") || EQUAL(pszOverride,"NULL") )
     515                 :     {
     516               0 :         nShapeType = SHPT_NULL;
     517               0 :         eType = wkbNone;
     518                 :     }
     519                 :     else
     520                 :     {
     521                 :         CPLError( CE_Failure, CPLE_NotSupported,
     522                 :                   "Unknown SHPT value of `%s' passed to Shapefile layer\n"
     523                 :                   "creation.  Creation aborted.\n",
     524               0 :                   pszOverride );
     525                 : 
     526               0 :         return NULL;
     527                 :     }
     528                 : 
     529            1183 :     if( nShapeType == -1 )
     530                 :     {
     531                 :         CPLError( CE_Failure, CPLE_NotSupported,
     532                 :                   "Geometry type of `%s' not supported in shapefiles.\n"
     533                 :                   "Type can be overridden with a layer creation option\n"
     534                 :                   "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/MULTIPOINTZ.\n",
     535               0 :                   OGRGeometryTypeToName(eType) );
     536               0 :         return NULL;
     537                 :     }
     538                 :     
     539                 : /* -------------------------------------------------------------------- */
     540                 : /*      What filename do we use, excluding the extension?               */
     541                 : /* -------------------------------------------------------------------- */
     542                 :     char *pszBasename;
     543                 : 
     544            1273 :     if(  bSingleFileDataSource && nLayers == 0 )
     545                 :     {
     546              90 :         char *pszPath = CPLStrdup(CPLGetPath(pszName));
     547              90 :         char *pszFBasename = CPLStrdup(CPLGetBasename(pszName));
     548                 : 
     549              90 :         pszBasename = CPLStrdup(CPLFormFilename(pszPath, pszFBasename, NULL));
     550                 : 
     551              90 :         CPLFree( pszFBasename );
     552              90 :         CPLFree( pszPath );
     553                 :     }
     554            1093 :     else if(  bSingleFileDataSource )
     555                 :     {
     556                 :         /* This is a very weird use case : the user creates/open a datasource */
     557                 :         /* made of a single shapefile 'foo.shp' and wants to add a new layer */
     558                 :         /* to it, 'bar'. So we create a new shapefile 'bar.shp' in the same */
     559                 :         /* directory as 'foo.shp' */
     560                 :         /* So technically, we will not be any longer a single file */
     561                 :         /* datasource ... Ahem ahem */
     562               1 :         char *pszPath = CPLStrdup(CPLGetPath(pszName));
     563               1 :         pszBasename = CPLStrdup(CPLFormFilename(pszPath,pszLayerName,NULL));
     564               1 :         CPLFree( pszPath );
     565                 :     }
     566                 :     else
     567            1092 :         pszBasename = CPLStrdup(CPLFormFilename(pszName,pszLayerName,NULL));
     568                 : 
     569                 : /* -------------------------------------------------------------------- */
     570                 : /*      Create the shapefile.                                           */
     571                 : /* -------------------------------------------------------------------- */
     572                 :     char        *pszFilename;
     573                 : 
     574            1183 :     if( nShapeType != SHPT_NULL )
     575                 :     {
     576            1180 :         pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "shp" ));
     577                 : 
     578            1180 :         hSHP = SHPCreate( pszFilename, nShapeType );
     579                 :         
     580            1180 :         if( hSHP == NULL )
     581                 :         {
     582                 :             CPLError( CE_Failure, CPLE_OpenFailed,
     583                 :                       "Failed to open Shapefile `%s'.\n",
     584               0 :                       pszFilename );
     585               0 :             CPLFree( pszFilename );
     586               0 :             CPLFree( pszBasename );
     587               0 :             return NULL;
     588                 :         }
     589            1180 :         CPLFree( pszFilename );
     590                 :     }
     591                 :     else
     592               3 :         hSHP = NULL;
     593                 : 
     594                 : /* -------------------------------------------------------------------- */
     595                 : /*      Has a specific LDID been specified by the caller?               */
     596                 : /* -------------------------------------------------------------------- */
     597            1183 :     const char *pszLDID = CSLFetchNameValue( papszOptions, "ENCODING" );
     598                 : 
     599                 : /* -------------------------------------------------------------------- */
     600                 : /*      Create a DBF file.                                              */
     601                 : /* -------------------------------------------------------------------- */
     602            1183 :     pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "dbf" ));
     603                 : 
     604            1183 :     if( pszLDID != NULL )
     605               0 :         hDBF = DBFCreateEx( pszFilename, pszLDID );
     606                 :     else
     607            1183 :         hDBF = DBFCreate( pszFilename );
     608                 : 
     609            1183 :     if( hDBF == NULL )
     610                 :     {
     611                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     612                 :                   "Failed to open Shape DBF file `%s'.\n",
     613               0 :                   pszFilename );
     614               0 :         CPLFree( pszFilename );
     615               0 :         CPLFree( pszBasename );
     616               0 :         SHPClose(hSHP);
     617               0 :         return NULL;
     618                 :     }
     619                 : 
     620            1183 :     CPLFree( pszFilename );
     621                 : 
     622                 : /* -------------------------------------------------------------------- */
     623                 : /*      Create the .prj file, if required.                              */
     624                 : /* -------------------------------------------------------------------- */
     625            1183 :     if( poSRS != NULL )
     626                 :     {
     627              80 :         char    *pszWKT = NULL;
     628              80 :         CPLString osPrjFile = CPLFormFilename( NULL, pszBasename, "prj");
     629                 :         VSILFILE    *fp;
     630                 : 
     631                 :         /* the shape layer needs it's own copy */
     632              80 :         poSRS = poSRS->Clone();
     633              80 :         poSRS->morphToESRI();
     634                 : 
     635              80 :         if( poSRS->exportToWkt( &pszWKT ) == OGRERR_NONE 
     636                 :             && (fp = VSIFOpenL( osPrjFile, "wt" )) != NULL )
     637                 :         {
     638              80 :             VSIFWriteL( pszWKT, strlen(pszWKT), 1, fp );
     639              80 :             VSIFCloseL( fp );
     640                 :         }
     641                 : 
     642              80 :         CPLFree( pszWKT );
     643                 : 
     644              80 :         poSRS->morphFromESRI();
     645                 :     }
     646                 : 
     647                 : /* -------------------------------------------------------------------- */
     648                 : /*      Create the layer object.                                        */
     649                 : /* -------------------------------------------------------------------- */
     650                 :     OGRShapeLayer       *poLayer;
     651                 : 
     652                 :     poLayer = new OGRShapeLayer( this, pszBasename, hSHP, hDBF, poSRS, TRUE, TRUE,
     653            1183 :                                  eType );
     654                 : 
     655            1183 :     CPLFree( pszBasename );
     656                 : 
     657                 : /* -------------------------------------------------------------------- */
     658                 : /*      Add layer to data source layer list.                            */
     659                 : /* -------------------------------------------------------------------- */
     660            1183 :     AddLayer(poLayer);
     661                 : 
     662            1183 :     return poLayer;
     663                 : }
     664                 : 
     665                 : /************************************************************************/
     666                 : /*                           TestCapability()                           */
     667                 : /************************************************************************/
     668                 : 
     669              74 : int OGRShapeDataSource::TestCapability( const char * pszCap )
     670                 : 
     671                 : {
     672              74 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     673              74 :         return bDSUpdate;
     674               0 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
     675               0 :         return bDSUpdate;
     676                 :     else
     677               0 :         return FALSE;
     678                 : }
     679                 : 
     680                 : /************************************************************************/
     681                 : /*                              GetLayer()                              */
     682                 : /************************************************************************/
     683                 : 
     684         1560695 : OGRLayer *OGRShapeDataSource::GetLayer( int iLayer )
     685                 : 
     686                 : {
     687         1560695 :     if( iLayer < 0 || iLayer >= nLayers )
     688               0 :         return NULL;
     689                 :     else
     690         1560695 :         return papoLayers[iLayer];
     691                 : }
     692                 : 
     693                 : /************************************************************************/
     694                 : /*                             ExecuteSQL()                             */
     695                 : /*                                                                      */
     696                 : /*      We override this to provide special handling of CREATE          */
     697                 : /*      SPATIAL INDEX commands.  Support forms are:                     */
     698                 : /*                                                                      */
     699                 : /*        CREATE SPATIAL INDEX ON layer_name [DEPTH n]                  */
     700                 : /*        DROP SPATIAL INDEX ON layer_name                              */
     701                 : /*        REPACK layer_name                                             */
     702                 : /*        RECOMPUTE EXTENT ON layer_name                                */
     703                 : /************************************************************************/
     704                 : 
     705             597 : OGRLayer * OGRShapeDataSource::ExecuteSQL( const char *pszStatement,
     706                 :                                            OGRGeometry *poSpatialFilter,
     707                 :                                            const char *pszDialect )
     708                 : 
     709                 : {
     710                 : /* ==================================================================== */
     711                 : /*      Handle command to drop a spatial index.                         */
     712                 : /* ==================================================================== */
     713             597 :     if( EQUALN(pszStatement, "REPACK ", 7) )
     714                 :     {
     715                 :         OGRShapeLayer *poLayer = (OGRShapeLayer *) 
     716               6 :             GetLayerByName( pszStatement + 7 );
     717                 : 
     718               6 :         if( poLayer != NULL )
     719               6 :             poLayer->Repack();
     720                 :         else
     721                 :         {
     722                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     723                 :                       "No such layer as '%s' in REPACK.", 
     724               0 :                       pszStatement + 7 );
     725                 :         }
     726               6 :         return NULL;
     727                 :     }
     728                 :     
     729                 : /* ==================================================================== */
     730                 : /*      Handle command to recompute extent                             */
     731                 : /* ==================================================================== */
     732             591 :     if( EQUALN(pszStatement, "RECOMPUTE EXTENT ON ", 20) )
     733                 :     {
     734                 :         OGRShapeLayer *poLayer = (OGRShapeLayer *) 
     735               3 :             GetLayerByName( pszStatement + 20 );
     736                 : 
     737               3 :         if( poLayer != NULL )
     738               2 :             poLayer->RecomputeExtent();
     739                 :         else
     740                 :         {
     741                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     742                 :                       "No such layer as '%s' in RECOMPUTE EXTENT.", 
     743               1 :                       pszStatement + 20 );
     744                 :         }
     745               3 :         return NULL;
     746                 :     }
     747                 :     
     748                 : /* ==================================================================== */
     749                 : /*      Handle command to drop a spatial index.                         */
     750                 : /* ==================================================================== */
     751             588 :     if( EQUALN(pszStatement, "DROP SPATIAL INDEX ON ", 22) )
     752                 :     {
     753                 :         OGRShapeLayer *poLayer = (OGRShapeLayer *) 
     754               2 :             GetLayerByName( pszStatement + 22 );
     755                 : 
     756               2 :         if( poLayer != NULL )
     757               2 :             poLayer->DropSpatialIndex();
     758                 :         else
     759                 :         {
     760                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     761                 :                       "No such layer as '%s' in DROP SPATIAL INDEX.", 
     762               0 :                       pszStatement + 19 );
     763                 :         }
     764               2 :         return NULL;
     765                 :     }
     766                 :     
     767                 : /* ==================================================================== */
     768                 : /*      Handle all comands except spatial index creation generically.   */
     769                 : /* ==================================================================== */
     770             586 :     if( !EQUALN(pszStatement,"CREATE SPATIAL INDEX ON ",24) )
     771                 :     {
     772             578 :         char **papszTokens = CSLTokenizeString( pszStatement );
     773             742 :         if( CSLCount(papszTokens) >=4
     774             148 :             && (EQUAL(papszTokens[0],"CREATE") || EQUAL(papszTokens[0],"DROP"))
     775               8 :             && EQUAL(papszTokens[1],"INDEX")
     776               8 :             && EQUAL(papszTokens[2],"ON") )
     777                 :         {
     778               8 :             OGRShapeLayer *poLayer = (OGRShapeLayer *) GetLayerByName(papszTokens[3]);
     779               8 :             if (poLayer != NULL)
     780               8 :                 poLayer->InitializeIndexSupport( poLayer->GetFullName() );
     781                 :         }
     782             578 :         CSLDestroy( papszTokens );
     783                 : 
     784                 :         return OGRDataSource::ExecuteSQL( pszStatement, poSpatialFilter, 
     785             578 :                                           pszDialect );
     786                 :     }
     787                 : 
     788                 : /* -------------------------------------------------------------------- */
     789                 : /*      Parse into keywords.                                            */
     790                 : /* -------------------------------------------------------------------- */
     791               8 :     char **papszTokens = CSLTokenizeString( pszStatement );
     792                 :     
     793              40 :     if( CSLCount(papszTokens) < 5
     794               8 :         || !EQUAL(papszTokens[0],"CREATE")
     795               8 :         || !EQUAL(papszTokens[1],"SPATIAL")
     796               8 :         || !EQUAL(papszTokens[2],"INDEX") 
     797               8 :         || !EQUAL(papszTokens[3],"ON") 
     798                 :         || CSLCount(papszTokens) > 7 
     799               0 :         || (CSLCount(papszTokens) == 7 && !EQUAL(papszTokens[5],"DEPTH")) )
     800                 :     {
     801               0 :         CSLDestroy( papszTokens );
     802                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     803                 :                   "Syntax error in CREATE SPATIAL INDEX command.\n"
     804                 :                   "Was '%s'\n"
     805                 :                   "Should be of form 'CREATE SPATIAL INDEX ON <table> [DEPTH <n>]'",
     806               0 :                   pszStatement );
     807               0 :         return NULL;
     808                 :     }
     809                 : 
     810                 : /* -------------------------------------------------------------------- */
     811                 : /*      Get depth if provided.                                          */
     812                 : /* -------------------------------------------------------------------- */
     813               8 :     int nDepth = 0;
     814               8 :     if( CSLCount(papszTokens) == 7 )
     815               0 :         nDepth = atoi(papszTokens[6]);
     816                 : 
     817                 : /* -------------------------------------------------------------------- */
     818                 : /*      What layer are we operating on.                                 */
     819                 : /* -------------------------------------------------------------------- */
     820               8 :     OGRShapeLayer *poLayer = (OGRShapeLayer *) GetLayerByName(papszTokens[4]);
     821                 : 
     822               8 :     if( poLayer == NULL )
     823                 :     {
     824                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     825                 :                   "Layer %s not recognised.", 
     826               0 :                   papszTokens[4] );
     827               0 :         CSLDestroy( papszTokens );
     828               0 :         return NULL;
     829                 :     }
     830                 : 
     831               8 :     CSLDestroy( papszTokens );
     832                 : 
     833               8 :     poLayer->CreateSpatialIndex( nDepth );
     834               8 :     return NULL;
     835                 : }
     836                 : 
     837                 : 
     838                 : /************************************************************************/
     839                 : /*                            DeleteLayer()                             */
     840                 : /************************************************************************/
     841                 : 
     842             508 : OGRErr OGRShapeDataSource::DeleteLayer( int iLayer )
     843                 : 
     844                 : {
     845                 :     char *pszFilename;
     846                 : 
     847                 : /* -------------------------------------------------------------------- */
     848                 : /*      Verify we are in update mode.                                   */
     849                 : /* -------------------------------------------------------------------- */
     850             508 :     if( !bDSUpdate )
     851                 :     {
     852                 :         CPLError( CE_Failure, CPLE_NoWriteAccess,
     853                 :                   "Data source %s opened read-only.\n"
     854                 :                   "Layer %d cannot be deleted.\n",
     855               0 :                   pszName, iLayer );
     856                 : 
     857               0 :         return OGRERR_FAILURE;
     858                 :     }
     859                 : 
     860             508 :     if( iLayer < 0 || iLayer >= nLayers )
     861                 :     {
     862                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     863                 :                   "Layer %d not in legal range of 0 to %d.", 
     864               0 :                   iLayer, nLayers-1 );
     865               0 :         return OGRERR_FAILURE;
     866                 :     }
     867                 : 
     868             508 :     OGRShapeLayer* poLayerToDelete = (OGRShapeLayer*) papoLayers[iLayer];
     869                 : 
     870             508 :     pszFilename = CPLStrdup(poLayerToDelete->GetFullName());
     871                 : 
     872             508 :     delete poLayerToDelete;
     873                 : 
     874           86968 :     while( iLayer < nLayers - 1 )
     875                 :     {
     876           85952 :         papoLayers[iLayer] = papoLayers[iLayer+1];
     877           85952 :         iLayer++;
     878                 :     }
     879                 : 
     880             508 :     nLayers--;
     881                 : 
     882             508 :     VSIUnlink( CPLResetExtension(pszFilename, "shp") );
     883             508 :     VSIUnlink( CPLResetExtension(pszFilename, "shx") );
     884             508 :     VSIUnlink( CPLResetExtension(pszFilename, "dbf") );
     885             508 :     VSIUnlink( CPLResetExtension(pszFilename, "prj") );
     886             508 :     VSIUnlink( CPLResetExtension(pszFilename, "qix") );
     887                 : 
     888             508 :     CPLFree( pszFilename );
     889                 : 
     890             508 :     return OGRERR_NONE;
     891                 : }
     892                 : 
     893                 : /************************************************************************/
     894                 : /*                          SetLastUsedLayer()                          */
     895                 : /************************************************************************/
     896                 : 
     897           48486 : void OGRShapeDataSource::SetLastUsedLayer( OGRShapeLayer* poLayer )
     898                 : {
     899                 :     /* We could remove that check and things would still work in */
     900                 :     /* 99.99% cases */
     901                 :     /* The only rationale for that test is to avoid breaking applications */
     902                 :     /* that would deal with layers of the same datasource in different */
     903                 :     /* threads. In GDAL < 1.9.0, this would work in most cases I can */
     904                 :     /* imagine as shapefile layers are pretty much independant from each */
     905                 :     /* others (although it has never been guaranteed to be a valid use case, */
     906                 :     /* and the shape driver is likely more the exception than the rule in */
     907                 :     /* permitting accessing layers from different threads !) */
     908                 :     /* Anyway the LRU list mechanism leaves the door open to concurrent accesses to it */
     909                 :     /* so when the datasource has not many layers, we don't try to build the */
     910                 :     /* LRU list to avoid concurrency issues. I haven't bothered making the analysis */
     911                 :     /* of how a mutex could be used to protect that (my intuition is that it would */
     912                 :     /* need to be placed at the beginning of OGRShapeLayer::TouchLayer() ) */
     913           48486 :     if (nLayers < MAX_SIMULTANEOUSLY_OPENED_LAYERS)
     914           41352 :         return;
     915                 : 
     916                 :     /* If we are already the MRU layer, nothing to do */
     917            7134 :     if (poLayer == poMRULayer)
     918            2622 :         return;
     919                 : 
     920                 :     //CPLDebug("SHAPE", "SetLastUsedLayer(%s)", poLayer->GetName());
     921                 : 
     922            4514 :     if (poLayer->poPrevLayer != NULL || poLayer->poNextLayer != NULL)
     923                 :     {
     924                 :         /* Remove current layer from its current place in the list */
     925               2 :         UnchainLayer(poLayer);
     926                 :     }
     927            4510 :     else if (nMRUListSize == MAX_SIMULTANEOUSLY_OPENED_LAYERS)
     928                 :     {
     929                 :         /* If we have reached the maximum allowed number of layers */
     930                 :         /* simultaneously opened, then close the LRU one that */
     931                 :         /* was still active until now */
     932            3809 :         CPLAssert(poLRULayer != NULL);
     933                 : 
     934            3809 :         poLRULayer->CloseFileDescriptors();
     935            3809 :         UnchainLayer(poLRULayer);
     936                 :     }
     937                 : 
     938                 :     /* Put current layer on top of MRU list */
     939            4512 :     CPLAssert(poLayer->poPrevLayer == NULL);
     940            4512 :     CPLAssert(poLayer->poNextLayer == NULL);
     941            4512 :     poLayer->poNextLayer = poMRULayer;
     942            4512 :     if (poMRULayer != NULL)
     943                 :     {
     944            4505 :         CPLAssert(poMRULayer->poPrevLayer == NULL);
     945            4505 :         poMRULayer->poPrevLayer = poLayer;
     946                 :     }
     947            4512 :     poMRULayer = poLayer;
     948            4512 :     if (poLRULayer == NULL)
     949               7 :         poLRULayer = poLayer;
     950            4512 :     nMRUListSize ++;
     951                 : }
     952                 : 
     953                 : 
     954                 : /************************************************************************/
     955                 : /*                            UnchainLayer()                            */
     956                 : /*                                                                      */
     957                 : /* Remove the layer from the MRU list                                   */
     958                 : /************************************************************************/
     959                 : 
     960            8569 : void OGRShapeDataSource::UnchainLayer( OGRShapeLayer* poLayer )
     961                 : {
     962                 :     //CPLDebug("SHAPE", "UnchainLayer(%s)", poLayer->GetName());
     963                 : 
     964            8569 :     OGRShapeLayer* poPrevLayer = poLayer->poPrevLayer;
     965            8569 :     OGRShapeLayer* poNextLayer = poLayer->poNextLayer;
     966                 : 
     967            8569 :     if (poPrevLayer != NULL)
     968            4500 :         CPLAssert(poPrevLayer->poNextLayer == poLayer);
     969            8569 :     if (poNextLayer != NULL)
     970             109 :         CPLAssert(poNextLayer->poPrevLayer == poLayer);
     971                 : 
     972            8569 :     if (poPrevLayer != NULL || poNextLayer != NULL || poLayer == poMRULayer)
     973            4512 :         nMRUListSize --;
     974                 : 
     975            8569 :     if (poLayer == poMRULayer)
     976              12 :         poMRULayer = poNextLayer;
     977            8569 :     if (poLayer == poLRULayer)
     978            4403 :         poLRULayer = poPrevLayer;
     979            8569 :     if (poPrevLayer != NULL)
     980            4500 :         poPrevLayer->poNextLayer = poNextLayer;
     981            8569 :     if (poNextLayer != NULL)
     982             109 :         poNextLayer->poPrevLayer = poPrevLayer;
     983            8569 :     poLayer->poPrevLayer = NULL;
     984            8569 :     poLayer->poNextLayer = NULL;
     985            8569 : }

Generated by: LCOV version 1.7