LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapedatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 364 304 83.5 %
Date: 2012-12-26 Functions: 16 13 81.2 %

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

Generated by: LCOV version 1.7