LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - ogrshapedatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 618 764 80.9 %
Date: 2025-01-18 12:42:00 Functions: 27 30 90.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRShapeDataSource class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogrshape.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <cstddef>
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : #include <memory>
      22             : #include <set>
      23             : #include <vector>
      24             : 
      25             : #include "cpl_conv.h"
      26             : #include "cpl_error.h"
      27             : #include "cpl_string.h"
      28             : #include "cpl_vsi.h"
      29             : #include "cpl_vsi_error.h"
      30             : #include "gdal.h"
      31             : #include "gdal_priv.h"
      32             : #include "ogr_core.h"
      33             : #include "ogr_geometry.h"
      34             : #include "ogr_spatialref.h"
      35             : #include "ogrlayerpool.h"
      36             : #include "ogrsf_frmts.h"
      37             : #include "shapefil.h"
      38             : #include "shp_vsi.h"
      39             : 
      40             : // #define IMMEDIATE_OPENING 1
      41             : 
      42             : constexpr int knREFRESH_LOCK_FILE_DELAY_SEC = 10;
      43             : 
      44             : /************************************************************************/
      45             : /*                          DS_SHPOpen()                                */
      46             : /************************************************************************/
      47             : 
      48        3590 : SHPHandle OGRShapeDataSource::DS_SHPOpen(const char *pszShapeFile,
      49             :                                          const char *pszAccess)
      50             : {
      51             :     // Do lazy shx loading for /vsicurl/
      52        3590 :     if (STARTS_WITH(pszShapeFile, "/vsicurl/") && strcmp(pszAccess, "r") == 0)
      53           0 :         pszAccess = "rl";
      54             : 
      55             :     const bool bRestoreSHX =
      56        3590 :         CPLTestBool(CPLGetConfigOption("SHAPE_RESTORE_SHX", "FALSE"));
      57        3590 :     SHPHandle hSHP = SHPOpenLLEx(
      58             :         pszShapeFile, pszAccess,
      59        3590 :         const_cast<SAHooks *>(VSI_SHP_GetHook(b2GBLimit)), bRestoreSHX);
      60             : 
      61        3590 :     if (hSHP != nullptr)
      62        3262 :         SHPSetFastModeReadObject(hSHP, TRUE);
      63        3590 :     return hSHP;
      64             : }
      65             : 
      66             : /************************************************************************/
      67             : /*                           DS_DBFOpen()                               */
      68             : /************************************************************************/
      69             : 
      70        3590 : DBFHandle OGRShapeDataSource::DS_DBFOpen(const char *pszDBFFile,
      71             :                                          const char *pszAccess)
      72             : {
      73             :     DBFHandle hDBF =
      74        3590 :         DBFOpenLL(pszDBFFile, pszAccess,
      75        3590 :                   const_cast<SAHooks *>(VSI_SHP_GetHook(b2GBLimit)));
      76        3590 :     return hDBF;
      77             : }
      78             : 
      79             : /************************************************************************/
      80             : /*                         OGRShapeDataSource()                         */
      81             : /************************************************************************/
      82             : 
      83        2718 : OGRShapeDataSource::OGRShapeDataSource()
      84             :     : papoLayers(nullptr), nLayers(0), bSingleFileDataSource(false),
      85        2718 :       poPool(new OGRLayerPool()),
      86        5436 :       b2GBLimit(CPLTestBool(CPLGetConfigOption("SHAPE_2GB_LIMIT", "FALSE")))
      87             : {
      88        2718 : }
      89             : 
      90             : /************************************************************************/
      91             : /*                             GetLayerNames()                          */
      92             : /************************************************************************/
      93             : 
      94           5 : std::vector<CPLString> OGRShapeDataSource::GetLayerNames() const
      95             : {
      96           5 :     std::vector<CPLString> res;
      97           5 :     const_cast<OGRShapeDataSource *>(this)->GetLayerCount();
      98          10 :     for (int i = 0; i < nLayers; i++)
      99             :     {
     100           5 :         res.emplace_back(papoLayers[i]->GetName());
     101             :     }
     102           5 :     return res;
     103             : }
     104             : 
     105             : /************************************************************************/
     106             : /*                        ~OGRShapeDataSource()                         */
     107             : /************************************************************************/
     108             : 
     109        5422 : OGRShapeDataSource::~OGRShapeDataSource()
     110             : 
     111             : {
     112        5422 :     std::vector<CPLString> layerNames;
     113        2711 :     if (!m_osTemporaryUnzipDir.empty())
     114             :     {
     115           5 :         layerNames = GetLayerNames();
     116             :     }
     117        7291 :     for (int i = 0; i < nLayers; i++)
     118             :     {
     119        4580 :         CPLAssert(nullptr != papoLayers[i]);
     120             : 
     121        4580 :         delete papoLayers[i];
     122             :     }
     123        2711 :     CPLFree(papoLayers);
     124        2711 :     nLayers = 0;
     125        2711 :     papoLayers = nullptr;
     126             : 
     127        2711 :     delete poPool;
     128             : 
     129        2711 :     RecompressIfNeeded(layerNames);
     130        2711 :     RemoveLockFile();
     131             : 
     132             :     // Free mutex & cond
     133        2711 :     if (m_poRefreshLockFileMutex)
     134             :     {
     135           0 :         CPLDestroyMutex(m_poRefreshLockFileMutex);
     136           0 :         m_poRefreshLockFileMutex = nullptr;
     137             :     }
     138        2711 :     if (m_poRefreshLockFileCond)
     139             :     {
     140           0 :         CPLDestroyCond(m_poRefreshLockFileCond);
     141           0 :         m_poRefreshLockFileCond = nullptr;
     142             :     }
     143        5422 : }
     144             : 
     145             : /************************************************************************/
     146             : /*                              OpenZip()                               */
     147             : /************************************************************************/
     148             : 
     149           6 : bool OGRShapeDataSource::OpenZip(GDALOpenInfo *poOpenInfo,
     150             :                                  const char *pszOriFilename)
     151             : {
     152           6 :     if (!Open(poOpenInfo, true))
     153           0 :         return false;
     154             : 
     155           6 :     SetDescription(pszOriFilename);
     156             : 
     157           6 :     m_bIsZip = true;
     158           6 :     m_bSingleLayerZip =
     159           6 :         EQUAL(CPLGetExtensionSafe(pszOriFilename).c_str(), "shz");
     160             : 
     161           6 :     if (!m_bSingleLayerZip)
     162             :     {
     163           2 :         CPLString osLockFile(GetDescription());
     164           1 :         osLockFile += ".gdal.lock";
     165             :         VSIStatBufL sStat;
     166           1 :         if (VSIStatL(osLockFile, &sStat) == 0 &&
     167           0 :             sStat.st_mtime < time(nullptr) - 2 * knREFRESH_LOCK_FILE_DELAY_SEC)
     168             :         {
     169           0 :             CPLDebug("Shape", "Deleting stalled %s", osLockFile.c_str());
     170           0 :             VSIUnlink(osLockFile);
     171             :         }
     172             :     }
     173             : 
     174           6 :     return true;
     175             : }
     176             : 
     177             : /************************************************************************/
     178             : /*                            CreateZip()                               */
     179             : /************************************************************************/
     180             : 
     181           3 : bool OGRShapeDataSource::CreateZip(const char *pszOriFilename)
     182             : {
     183           3 :     CPLAssert(nLayers == 0);
     184             : 
     185           3 :     void *hZIP = CPLCreateZip(pszOriFilename, nullptr);
     186           3 :     if (!hZIP)
     187           1 :         return false;
     188           2 :     if (CPLCloseZip(hZIP) != CE_None)
     189           0 :         return false;
     190           2 :     eAccess = GA_Update;
     191           2 :     m_bIsZip = true;
     192           2 :     m_bSingleLayerZip =
     193           2 :         EQUAL(CPLGetExtensionSafe(pszOriFilename).c_str(), "shz");
     194           2 :     return true;
     195             : }
     196             : 
     197             : /************************************************************************/
     198             : /*                                Open()                                */
     199             : /************************************************************************/
     200             : 
     201        2715 : bool OGRShapeDataSource::Open(GDALOpenInfo *poOpenInfo, bool bTestOpen,
     202             :                               bool bForceSingleFileDataSource)
     203             : 
     204             : {
     205        2715 :     CPLAssert(nLayers == 0);
     206             : 
     207        2715 :     const char *pszNewName = poOpenInfo->pszFilename;
     208        2715 :     const bool bUpdate = poOpenInfo->eAccess == GA_Update;
     209        2715 :     CPLAssert(papszOpenOptions == nullptr);
     210        2715 :     papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
     211             : 
     212        2715 :     eAccess = poOpenInfo->eAccess;
     213             : 
     214        2715 :     bSingleFileDataSource = CPL_TO_BOOL(bForceSingleFileDataSource);
     215             : 
     216             :     /* -------------------------------------------------------------------- */
     217             :     /*      If bSingleFileDataSource is TRUE we don't try to do anything    */
     218             :     /*      else.                                                           */
     219             :     /*      This is only utilized when the OGRShapeDriver::Create()         */
     220             :     /*      method wants to create a stub OGRShapeDataSource for a          */
     221             :     /*      single shapefile.  The driver will take care of creating the    */
     222             :     /*      file by calling ICreateLayer().                                 */
     223             :     /* -------------------------------------------------------------------- */
     224        2715 :     if (bSingleFileDataSource)
     225         423 :         return true;
     226             : 
     227             :     /* -------------------------------------------------------------------- */
     228             :     /*      Is the given path a directory or a regular file?                */
     229             :     /* -------------------------------------------------------------------- */
     230        2292 :     if (!poOpenInfo->bStatOK)
     231             :     {
     232           0 :         if (!bTestOpen)
     233           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     234             :                      "%s is neither a file or directory, Shape access failed.",
     235             :                      pszNewName);
     236             : 
     237           0 :         return false;
     238             :     }
     239             : 
     240             :     /* -------------------------------------------------------------------- */
     241             :     /*      Build a list of filenames we figure are Shape files.            */
     242             :     /* -------------------------------------------------------------------- */
     243        2292 :     if (!poOpenInfo->bIsDirectory)
     244             :     {
     245        1245 :         if (!OpenFile(pszNewName, bUpdate))
     246             :         {
     247           1 :             if (!bTestOpen)
     248           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     249             :                          "Failed to open shapefile %s.  "
     250             :                          "It may be corrupt or read-only file accessed in "
     251             :                          "update mode.",
     252             :                          pszNewName);
     253             : 
     254           1 :             return false;
     255             :         }
     256             : 
     257        1244 :         bSingleFileDataSource = true;
     258             : 
     259        1244 :         return true;
     260             :     }
     261             :     else
     262             :     {
     263        1047 :         char **papszCandidates = VSIReadDir(pszNewName);
     264        1047 :         const int nCandidateCount = CSLCount(papszCandidates);
     265        1047 :         bool bMightBeOldCoverage = false;
     266        1047 :         std::set<CPLString> osLayerNameSet;
     267             : 
     268       50757 :         for (int iCan = 0; iCan < nCandidateCount; iCan++)
     269             :         {
     270       49710 :             const char *pszCandidate = papszCandidates[iCan];
     271       49710 :             CPLString osLayerName(CPLGetBasenameSafe(pszCandidate));
     272             : #ifdef _WIN32
     273             :             // On Windows, as filenames are case insensitive, a shapefile layer
     274             :             // can be made of foo.shp and FOO.DBF, so to detect unique layer
     275             :             // names, put them upper case in the unique set used for detection.
     276             :             osLayerName.toupper();
     277             : #endif
     278             : 
     279       49710 :             if (EQUAL(pszCandidate, "ARC"))
     280           0 :                 bMightBeOldCoverage = true;
     281             : 
     282       49710 :             if (strlen(pszCandidate) < 4 ||
     283       44009 :                 !EQUAL(pszCandidate + strlen(pszCandidate) - 4, ".shp"))
     284       46312 :                 continue;
     285             : 
     286        3398 :             char *pszFilename = CPLStrdup(
     287        6796 :                 CPLFormFilenameSafe(pszNewName, pszCandidate, nullptr).c_str());
     288             : 
     289        3398 :             osLayerNameSet.insert(osLayerName);
     290             : #ifdef IMMEDIATE_OPENING
     291             :             if (!OpenFile(pszFilename, bUpdate) && !bTestOpen)
     292             :             {
     293             :                 CPLError(CE_Failure, CPLE_OpenFailed,
     294             :                          "Failed to open shapefile %s.  "
     295             :                          "It may be corrupt or read-only file accessed in "
     296             :                          "update mode.",
     297             :                          pszFilename);
     298             :                 CPLFree(pszFilename);
     299             :                 CSLDestroy(papszCandidates);
     300             :                 return false;
     301             :             }
     302             : #else
     303        3398 :             oVectorLayerName.push_back(pszFilename);
     304             : #endif
     305        3398 :             CPLFree(pszFilename);
     306             :         }
     307             : 
     308             :         // Try and .dbf files without apparent associated shapefiles.
     309       50757 :         for (int iCan = 0; iCan < nCandidateCount; iCan++)
     310             :         {
     311       49710 :             const char *pszCandidate = papszCandidates[iCan];
     312       49710 :             const std::string osLayerNameOri = CPLGetBasenameSafe(pszCandidate);
     313       49710 :             CPLString osLayerName(osLayerNameOri);
     314             : #ifdef _WIN32
     315             :             osLayerName.toupper();
     316             : #endif
     317             : 
     318             :             // We don't consume .dbf files in a directory that looks like
     319             :             // an old style Arc/Info (for PC?) that unless we found at least
     320             :             // some shapefiles.  See Bug 493.
     321       49710 :             if (bMightBeOldCoverage && osLayerNameSet.empty())
     322           0 :                 continue;
     323             : 
     324       49710 :             if (strlen(pszCandidate) < 4 ||
     325       44009 :                 !EQUAL(pszCandidate + strlen(pszCandidate) - 4, ".dbf"))
     326       45754 :                 continue;
     327             : 
     328        3956 :             if (osLayerNameSet.find(osLayerName) != osLayerNameSet.end())
     329        3397 :                 continue;
     330             : 
     331             :             // We don't want to access .dbf files with an associated .tab
     332             :             // file, or it will never get recognised as a mapinfo dataset.
     333         559 :             bool bFoundTAB = false;
     334       38191 :             for (int iCan2 = 0; iCan2 < nCandidateCount; iCan2++)
     335             :             {
     336       37632 :                 const char *pszCandidate2 = papszCandidates[iCan2];
     337             : 
     338       37632 :                 if (EQUALN(pszCandidate2, osLayerNameOri.c_str(),
     339       38922 :                            osLayerNameOri.size()) &&
     340        1290 :                     EQUAL(pszCandidate2 + osLayerNameOri.size(), ".tab"))
     341           0 :                     bFoundTAB = true;
     342             :             }
     343             : 
     344         559 :             if (bFoundTAB)
     345           0 :                 continue;
     346             : 
     347         559 :             char *pszFilename = CPLStrdup(
     348        1118 :                 CPLFormFilenameSafe(pszNewName, pszCandidate, nullptr).c_str());
     349             : 
     350         559 :             osLayerNameSet.insert(osLayerName);
     351             : 
     352             : #ifdef IMMEDIATE_OPENING
     353             :             if (!OpenFile(pszFilename, bUpdate) && !bTestOpen)
     354             :             {
     355             :                 CPLError(CE_Failure, CPLE_OpenFailed,
     356             :                          "Failed to open dbf file %s.  "
     357             :                          "It may be corrupt or read-only file accessed in "
     358             :                          "update mode.",
     359             :                          pszFilename);
     360             :                 CPLFree(pszFilename);
     361             :                 CSLDestroy(papszCandidates);
     362             :                 return false;
     363             :             }
     364             : #else
     365         559 :             oVectorLayerName.push_back(pszFilename);
     366             : #endif
     367         559 :             CPLFree(pszFilename);
     368             :         }
     369             : 
     370        1047 :         CSLDestroy(papszCandidates);
     371             : 
     372             : #ifdef IMMEDIATE_OPENING
     373             :         const int nDirLayers = nLayers;
     374             : #else
     375        1047 :         const int nDirLayers = static_cast<int>(oVectorLayerName.size());
     376             : #endif
     377             : 
     378        1047 :         CPLErrorReset();
     379             : 
     380        1047 :         return nDirLayers > 0 || !bTestOpen;
     381             :     }
     382             : }
     383             : 
     384             : /************************************************************************/
     385             : /*                              OpenFile()                              */
     386             : /************************************************************************/
     387             : 
     388        3556 : bool OGRShapeDataSource::OpenFile(const char *pszNewName, bool bUpdate)
     389             : 
     390             : {
     391        7112 :     const std::string osExtension = CPLGetExtensionSafe(pszNewName);
     392             : 
     393        3556 :     if (!EQUAL(osExtension.c_str(), "shp") &&
     394        3900 :         !EQUAL(osExtension.c_str(), "shx") &&
     395         344 :         !EQUAL(osExtension.c_str(), "dbf"))
     396           0 :         return false;
     397             : 
     398             :     /* -------------------------------------------------------------------- */
     399             :     /*      SHPOpen() should include better (CPL based) error reporting,    */
     400             :     /*      and we should be trying to distinguish at this point whether    */
     401             :     /*      failure is a result of trying to open a non-shapefile, or       */
     402             :     /*      whether it was a shapefile and we want to report the error      */
     403             :     /*      up.                                                             */
     404             :     /*                                                                      */
     405             :     /*      Care is taken to suppress the error and only reissue it if      */
     406             :     /*      we think it is appropriate.                                     */
     407             :     /* -------------------------------------------------------------------- */
     408             :     const bool bRealUpdateAccess =
     409        3556 :         bUpdate && (!IsZip() || !GetTemporaryUnzipDir().empty());
     410        3556 :     CPLErrorReset();
     411        3556 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     412        3556 :     SHPHandle hSHP = bRealUpdateAccess ? DS_SHPOpen(pszNewName, "r+")
     413        1925 :                                        : DS_SHPOpen(pszNewName, "r");
     414        3556 :     CPLPopErrorHandler();
     415             : 
     416             :     const bool bRestoreSHX =
     417        3556 :         CPLTestBool(CPLGetConfigOption("SHAPE_RESTORE_SHX", "FALSE"));
     418        3557 :     if (bRestoreSHX && EQUAL(CPLGetExtensionSafe(pszNewName).c_str(), "dbf") &&
     419           1 :         CPLGetLastErrorMsg()[0] != '\0')
     420             :     {
     421           2 :         CPLString osMsg = CPLGetLastErrorMsg();
     422             : 
     423           1 :         CPLError(CE_Warning, CPLE_AppDefined, "%s", osMsg.c_str());
     424             :     }
     425             :     else
     426             :     {
     427        3882 :         if (hSHP == nullptr &&
     428        3882 :             (!EQUAL(CPLGetExtensionSafe(pszNewName).c_str(), "dbf") ||
     429         326 :              strstr(CPLGetLastErrorMsg(), ".shp") == nullptr))
     430             :         {
     431           1 :             CPLString osMsg = CPLGetLastErrorMsg();
     432             : 
     433           1 :             CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
     434             : 
     435           1 :             return false;
     436             :         }
     437        3554 :         CPLErrorReset();
     438             :     }
     439             : 
     440             :     /* -------------------------------------------------------------------- */
     441             :     /*      Open the .dbf file, if it exists.  To open a dbf file, the      */
     442             :     /*      filename has to either refer to a successfully opened shp       */
     443             :     /*      file or has to refer to the actual .dbf file.                   */
     444             :     /* -------------------------------------------------------------------- */
     445        3555 :     DBFHandle hDBF = nullptr;
     446        3882 :     if (hSHP != nullptr ||
     447        3882 :         EQUAL(CPLGetExtensionSafe(pszNewName).c_str(), "dbf"))
     448             :     {
     449        3555 :         if (bRealUpdateAccess)
     450             :         {
     451        1631 :             hDBF = DS_DBFOpen(pszNewName, "r+");
     452        1631 :             if (hSHP != nullptr && hDBF == nullptr)
     453             :             {
     454          22 :                 for (int i = 0; i < 2; i++)
     455             :                 {
     456             :                     VSIStatBufL sStat;
     457             :                     const std::string osDBFName = CPLResetExtensionSafe(
     458          15 :                         pszNewName, (i == 0) ? "dbf" : "DBF");
     459          15 :                     VSILFILE *fp = nullptr;
     460          15 :                     if (VSIStatExL(osDBFName.c_str(), &sStat,
     461          15 :                                    VSI_STAT_EXISTS_FLAG) == 0)
     462             :                     {
     463           1 :                         fp = VSIFOpenL(osDBFName.c_str(), "r+");
     464           1 :                         if (fp == nullptr)
     465             :                         {
     466           1 :                             CPLError(CE_Failure, CPLE_OpenFailed,
     467             :                                      "%s exists, "
     468             :                                      "but cannot be opened in update mode",
     469             :                                      osDBFName.c_str());
     470           1 :                             SHPClose(hSHP);
     471           1 :                             return false;
     472             :                         }
     473           0 :                         VSIFCloseL(fp);
     474           0 :                         break;
     475             :                     }
     476             :                 }
     477             :             }
     478             :         }
     479             :         else
     480             :         {
     481        1924 :             hDBF = DS_DBFOpen(pszNewName, "r");
     482             :         }
     483             :     }
     484             :     else
     485             :     {
     486           0 :         hDBF = nullptr;
     487             :     }
     488             : 
     489        3554 :     if (hDBF == nullptr && hSHP == nullptr)
     490           0 :         return false;
     491             : 
     492             :     /* -------------------------------------------------------------------- */
     493             :     /*      Create the layer object.                                        */
     494             :     /* -------------------------------------------------------------------- */
     495             :     OGRShapeLayer *poLayer = new OGRShapeLayer(
     496             :         this, pszNewName, hSHP, hDBF,
     497             :         /* poSRS = */ nullptr,
     498             :         /* bSRSSet = */ false,
     499        3554 :         /* osPrjFilename = */ std::string(), bUpdate, wkbNone);
     500        3554 :     poLayer->SetModificationDate(
     501        3554 :         CSLFetchNameValue(papszOpenOptions, "DBF_DATE_LAST_UPDATE"));
     502        3554 :     poLayer->SetAutoRepack(CPLFetchBool(papszOpenOptions, "AUTO_REPACK", true));
     503        3554 :     poLayer->SetWriteDBFEOFChar(
     504        3554 :         CPLFetchBool(papszOpenOptions, "DBF_EOF_CHAR", true));
     505             : 
     506             :     /* -------------------------------------------------------------------- */
     507             :     /*      Add layer to data source layer list.                            */
     508             :     /* -------------------------------------------------------------------- */
     509        3554 :     AddLayer(poLayer);
     510             : 
     511        3554 :     return true;
     512             : }
     513             : 
     514             : /************************************************************************/
     515             : /*                             AddLayer()                               */
     516             : /************************************************************************/
     517             : 
     518        5126 : void OGRShapeDataSource::AddLayer(OGRShapeLayer *poLayer)
     519             : {
     520        5126 :     papoLayers = reinterpret_cast<OGRShapeLayer **>(
     521        5126 :         CPLRealloc(papoLayers, sizeof(OGRShapeLayer *) * (nLayers + 1)));
     522        5126 :     papoLayers[nLayers++] = poLayer;
     523             : 
     524             :     // If we reach the limit, then register all the already opened layers
     525             :     // Technically this code would not be necessary if there was not the
     526             :     // following initial test in SetLastUsedLayer() :
     527             :     //      if (nLayers < MAX_SIMULTANEOUSLY_OPENED_LAYERS)
     528             :     //         return;
     529        5131 :     if (nLayers == poPool->GetMaxSimultaneouslyOpened() &&
     530           5 :         poPool->GetSize() == 0)
     531             :     {
     532         505 :         for (int i = 0; i < nLayers; i++)
     533         500 :             poPool->SetLastUsedLayer(papoLayers[i]);
     534             :     }
     535        5126 : }
     536             : 
     537             : /************************************************************************/
     538             : /*                        LaunderLayerName()                            */
     539             : /************************************************************************/
     540             : 
     541        1155 : static CPLString LaunderLayerName(const char *pszLayerName)
     542             : {
     543        2310 :     std::string osRet(CPLLaunderForFilenameSafe(pszLayerName, nullptr));
     544        1155 :     if (osRet != pszLayerName)
     545             :     {
     546           1 :         CPLError(CE_Warning, CPLE_AppDefined,
     547             :                  "Invalid layer name for a shapefile: %s. Laundered to %s.",
     548             :                  pszLayerName, osRet.c_str());
     549             :     }
     550        2310 :     return osRet;
     551             : }
     552             : 
     553             : /************************************************************************/
     554             : /*                           ICreateLayer()                             */
     555             : /************************************************************************/
     556             : 
     557             : OGRLayer *
     558        1582 : OGRShapeDataSource::ICreateLayer(const char *pszLayerName,
     559             :                                  const OGRGeomFieldDefn *poGeomFieldDefn,
     560             :                                  CSLConstList papszOptions)
     561             : 
     562             : {
     563             :     // To ensure that existing layers are created.
     564        1582 :     GetLayerCount();
     565             : 
     566        1582 :     auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
     567             :     const auto poSRS =
     568        1582 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
     569             : 
     570             :     /* -------------------------------------------------------------------- */
     571             :     /*      Check that the layer doesn't already exist.                     */
     572             :     /* -------------------------------------------------------------------- */
     573        1582 :     if (GetLayerByName(pszLayerName) != nullptr)
     574             :     {
     575           2 :         CPLError(CE_Failure, CPLE_AppDefined, "Layer '%s' already exists",
     576             :                  pszLayerName);
     577           2 :         return nullptr;
     578             :     }
     579             : 
     580             :     /* -------------------------------------------------------------------- */
     581             :     /*      Verify we are in update mode.                                   */
     582             :     /* -------------------------------------------------------------------- */
     583        1580 :     if (eAccess == GA_ReadOnly)
     584             :     {
     585           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     586             :                  "Data source %s opened read-only.  "
     587             :                  "New layer %s cannot be created.",
     588           0 :                  GetDescription(), pszLayerName);
     589             : 
     590           0 :         return nullptr;
     591             :     }
     592             : 
     593        1580 :     if (m_bIsZip && m_bSingleLayerZip && nLayers == 1)
     594             :     {
     595           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     596             :                  ".shz only supports one single layer");
     597           1 :         return nullptr;
     598             :     }
     599             : 
     600        1579 :     if (!UncompressIfNeeded())
     601           0 :         return nullptr;
     602             : 
     603             :     /* -------------------------------------------------------------------- */
     604             :     /*      Figure out what type of layer we need.                          */
     605             :     /* -------------------------------------------------------------------- */
     606        1579 :     int nShapeType = -1;
     607             : 
     608        1579 :     if (wkbFlatten(eType) == wkbUnknown || eType == wkbLineString)
     609        1252 :         nShapeType = SHPT_ARC;
     610         327 :     else if (eType == wkbPoint)
     611          41 :         nShapeType = SHPT_POINT;
     612         286 :     else if (eType == wkbPolygon || eType == wkbTriangle)
     613         111 :         nShapeType = SHPT_POLYGON;
     614         175 :     else if (eType == wkbMultiPoint)
     615           7 :         nShapeType = SHPT_MULTIPOINT;
     616         168 :     else if (eType == wkbPoint25D)
     617           6 :         nShapeType = SHPT_POINTZ;
     618         162 :     else if (eType == wkbPointM)
     619           2 :         nShapeType = SHPT_POINTM;
     620         160 :     else if (eType == wkbPointZM)
     621           2 :         nShapeType = SHPT_POINTZ;
     622         158 :     else if (eType == wkbLineString25D)
     623          11 :         nShapeType = SHPT_ARCZ;
     624         147 :     else if (eType == wkbLineStringM)
     625           2 :         nShapeType = SHPT_ARCM;
     626         145 :     else if (eType == wkbLineStringZM)
     627           2 :         nShapeType = SHPT_ARCZ;
     628         143 :     else if (eType == wkbMultiLineString)
     629          12 :         nShapeType = SHPT_ARC;
     630         131 :     else if (eType == wkbMultiLineString25D)
     631           5 :         nShapeType = SHPT_ARCZ;
     632         126 :     else if (eType == wkbMultiLineStringM)
     633           1 :         nShapeType = SHPT_ARCM;
     634         125 :     else if (eType == wkbMultiLineStringZM)
     635           1 :         nShapeType = SHPT_ARCZ;
     636         124 :     else if (eType == wkbPolygon25D || eType == wkbTriangleZ)
     637          12 :         nShapeType = SHPT_POLYGONZ;
     638         112 :     else if (eType == wkbPolygonM || eType == wkbTriangleM)
     639           2 :         nShapeType = SHPT_POLYGONM;
     640         110 :     else if (eType == wkbPolygonZM || eType == wkbTriangleZM)
     641           2 :         nShapeType = SHPT_POLYGONZ;
     642         108 :     else if (eType == wkbMultiPolygon)
     643          36 :         nShapeType = SHPT_POLYGON;
     644          72 :     else if (eType == wkbMultiPolygon25D)
     645           5 :         nShapeType = SHPT_POLYGONZ;
     646          67 :     else if (eType == wkbMultiPolygonM)
     647           1 :         nShapeType = SHPT_POLYGONM;
     648          66 :     else if (eType == wkbMultiPolygonZM)
     649           1 :         nShapeType = SHPT_POLYGONZ;
     650          65 :     else if (eType == wkbMultiPoint25D)
     651           6 :         nShapeType = SHPT_MULTIPOINTZ;
     652          59 :     else if (eType == wkbMultiPointM)
     653           2 :         nShapeType = SHPT_MULTIPOINTM;
     654          57 :     else if (eType == wkbMultiPointZM)
     655           2 :         nShapeType = SHPT_MULTIPOINTZ;
     656         106 :     else if (wkbFlatten(eType) == wkbTIN ||
     657          51 :              wkbFlatten(eType) == wkbPolyhedralSurface)
     658           4 :         nShapeType = SHPT_MULTIPATCH;
     659          51 :     else if (eType == wkbNone)
     660          47 :         nShapeType = SHPT_NULL;
     661             : 
     662             :     /* -------------------------------------------------------------------- */
     663             :     /*      Has the application overridden this with a special creation     */
     664             :     /*      option?                                                         */
     665             :     /* -------------------------------------------------------------------- */
     666        1579 :     const char *pszOverride = CSLFetchNameValue(papszOptions, "SHPT");
     667             : 
     668        1579 :     if (pszOverride == nullptr)
     669             :     {
     670             :         /* ignore */;
     671             :     }
     672          28 :     else if (EQUAL(pszOverride, "POINT"))
     673             :     {
     674           1 :         nShapeType = SHPT_POINT;
     675           1 :         eType = wkbPoint;
     676             :     }
     677          27 :     else if (EQUAL(pszOverride, "ARC"))
     678             :     {
     679           2 :         nShapeType = SHPT_ARC;
     680           2 :         eType = wkbLineString;
     681             :     }
     682          25 :     else if (EQUAL(pszOverride, "POLYGON"))
     683             :     {
     684           2 :         nShapeType = SHPT_POLYGON;
     685           2 :         eType = wkbPolygon;
     686             :     }
     687          23 :     else if (EQUAL(pszOverride, "MULTIPOINT"))
     688             :     {
     689           1 :         nShapeType = SHPT_MULTIPOINT;
     690           1 :         eType = wkbMultiPoint;
     691             :     }
     692          22 :     else if (EQUAL(pszOverride, "POINTZ"))
     693             :     {
     694           1 :         nShapeType = SHPT_POINTZ;
     695           1 :         eType = wkbPoint25D;
     696             :     }
     697          21 :     else if (EQUAL(pszOverride, "ARCZ"))
     698             :     {
     699           2 :         nShapeType = SHPT_ARCZ;
     700           2 :         eType = wkbLineString25D;
     701             :     }
     702          19 :     else if (EQUAL(pszOverride, "POLYGONZ"))
     703             :     {
     704           4 :         nShapeType = SHPT_POLYGONZ;
     705           4 :         eType = wkbPolygon25D;
     706             :     }
     707          15 :     else if (EQUAL(pszOverride, "MULTIPOINTZ"))
     708             :     {
     709           1 :         nShapeType = SHPT_MULTIPOINTZ;
     710           1 :         eType = wkbMultiPoint25D;
     711             :     }
     712          14 :     else if (EQUAL(pszOverride, "POINTM"))
     713             :     {
     714           1 :         nShapeType = SHPT_POINTM;
     715           1 :         eType = wkbPointM;
     716             :     }
     717          13 :     else if (EQUAL(pszOverride, "ARCM"))
     718             :     {
     719           2 :         nShapeType = SHPT_ARCM;
     720           2 :         eType = wkbLineStringM;
     721             :     }
     722          11 :     else if (EQUAL(pszOverride, "POLYGONM"))
     723             :     {
     724           2 :         nShapeType = SHPT_POLYGONM;
     725           2 :         eType = wkbPolygonM;
     726             :     }
     727           9 :     else if (EQUAL(pszOverride, "MULTIPOINTM"))
     728             :     {
     729           1 :         nShapeType = SHPT_MULTIPOINTM;
     730           1 :         eType = wkbMultiPointM;
     731             :     }
     732           8 :     else if (EQUAL(pszOverride, "POINTZM"))
     733             :     {
     734           1 :         nShapeType = SHPT_POINTZ;
     735           1 :         eType = wkbPointZM;
     736             :     }
     737           7 :     else if (EQUAL(pszOverride, "ARCZM"))
     738             :     {
     739           2 :         nShapeType = SHPT_ARCZ;
     740           2 :         eType = wkbLineStringZM;
     741             :     }
     742           5 :     else if (EQUAL(pszOverride, "POLYGONZM"))
     743             :     {
     744           2 :         nShapeType = SHPT_POLYGONZ;
     745           2 :         eType = wkbPolygonZM;
     746             :     }
     747           3 :     else if (EQUAL(pszOverride, "MULTIPOINTZM"))
     748             :     {
     749           1 :         nShapeType = SHPT_MULTIPOINTZ;
     750           1 :         eType = wkbMultiPointZM;
     751             :     }
     752           2 :     else if (EQUAL(pszOverride, "MULTIPATCH"))
     753             :     {
     754           2 :         nShapeType = SHPT_MULTIPATCH;
     755           2 :         eType = wkbUnknown;  // not ideal...
     756             :     }
     757           0 :     else if (EQUAL(pszOverride, "NONE") || EQUAL(pszOverride, "NULL"))
     758             :     {
     759           0 :         nShapeType = SHPT_NULL;
     760           0 :         eType = wkbNone;
     761             :     }
     762             :     else
     763             :     {
     764           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     765             :                  "Unknown SHPT value of `%s' passed to Shapefile layer"
     766             :                  "creation.  Creation aborted.",
     767             :                  pszOverride);
     768             : 
     769           0 :         return nullptr;
     770             :     }
     771             : 
     772        1579 :     if (nShapeType == -1)
     773             :     {
     774           4 :         CPLError(CE_Failure, CPLE_NotSupported,
     775             :                  "Geometry type of `%s' not supported in shapefiles.  "
     776             :                  "Type can be overridden with a layer creation option "
     777             :                  "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/"
     778             :                  "MULTIPOINTZ/MULTIPATCH.",
     779             :                  OGRGeometryTypeToName(eType));
     780           4 :         return nullptr;
     781             :     }
     782             : 
     783             :     /* -------------------------------------------------------------------- */
     784             :     /*      What filename do we use, excluding the extension?               */
     785             :     /* -------------------------------------------------------------------- */
     786        1575 :     char *pszFilenameWithoutExt = nullptr;
     787             : 
     788        1575 :     if (bSingleFileDataSource && nLayers == 0)
     789             :     {
     790         420 :         char *pszPath = CPLStrdup(CPLGetPathSafe(GetDescription()).c_str());
     791             :         char *pszFBasename =
     792         420 :             CPLStrdup(CPLGetBasenameSafe(GetDescription()).c_str());
     793             : 
     794         420 :         pszFilenameWithoutExt = CPLStrdup(
     795         840 :             CPLFormFilenameSafe(pszPath, pszFBasename, nullptr).c_str());
     796             : 
     797         420 :         CPLFree(pszFBasename);
     798         420 :         CPLFree(pszPath);
     799             :     }
     800        1155 :     else if (bSingleFileDataSource)
     801             :     {
     802             :         // This is a very weird use case : the user creates/open a datasource
     803             :         // made of a single shapefile 'foo.shp' and wants to add a new layer
     804             :         // to it, 'bar'. So we create a new shapefile 'bar.shp' in the same
     805             :         // directory as 'foo.shp'
     806             :         // So technically, we will not be any longer a single file
     807             :         // datasource ... Ahem ahem.
     808          16 :         char *pszPath = CPLStrdup(CPLGetPathSafe(GetDescription()).c_str());
     809          16 :         pszFilenameWithoutExt = CPLStrdup(
     810          32 :             CPLFormFilenameSafe(pszPath, LaunderLayerName(pszLayerName).c_str(),
     811             :                                 nullptr)
     812             :                 .c_str());
     813          16 :         CPLFree(pszPath);
     814             :     }
     815             :     else
     816             :     {
     817        1139 :         const std::string osDir(m_osTemporaryUnzipDir.empty()
     818        1137 :                                     ? std::string(GetDescription())
     819        1139 :                                     : m_osTemporaryUnzipDir);
     820        1139 :         pszFilenameWithoutExt = CPLStrdup(
     821        2278 :             CPLFormFilenameSafe(osDir.c_str(),
     822        2278 :                                 LaunderLayerName(pszLayerName).c_str(), nullptr)
     823             :                 .c_str());
     824             :     }
     825             : 
     826             :     /* -------------------------------------------------------------------- */
     827             :     /*      Create the shapefile.                                           */
     828             :     /* -------------------------------------------------------------------- */
     829             :     const bool l_b2GBLimit =
     830        1575 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "2GB_LIMIT", "FALSE"));
     831             : 
     832        1575 :     SHPHandle hSHP = nullptr;
     833             : 
     834        1575 :     if (nShapeType != SHPT_NULL)
     835             :     {
     836        1528 :         char *pszFilename = CPLStrdup(
     837        3056 :             CPLFormFilenameSafe(nullptr, pszFilenameWithoutExt, "shp").c_str());
     838             : 
     839        1528 :         hSHP = SHPCreateLL(pszFilename, nShapeType,
     840             :                            const_cast<SAHooks *>(VSI_SHP_GetHook(l_b2GBLimit)));
     841             : 
     842        1528 :         if (hSHP == nullptr)
     843             :         {
     844           2 :             CPLFree(pszFilename);
     845           2 :             CPLFree(pszFilenameWithoutExt);
     846           2 :             return nullptr;
     847             :         }
     848             : 
     849        1526 :         SHPSetFastModeReadObject(hSHP, TRUE);
     850             : 
     851        1526 :         CPLFree(pszFilename);
     852             :     }
     853             : 
     854             :     /* -------------------------------------------------------------------- */
     855             :     /*      Has a specific LDID been specified by the caller?               */
     856             :     /* -------------------------------------------------------------------- */
     857        1573 :     const char *pszLDID = CSLFetchNameValue(papszOptions, "ENCODING");
     858             : 
     859             :     /* -------------------------------------------------------------------- */
     860             :     /*      Create a DBF file.                                              */
     861             :     /* -------------------------------------------------------------------- */
     862        1573 :     char *pszFilename = CPLStrdup(
     863        3146 :         CPLFormFilenameSafe(nullptr, pszFilenameWithoutExt, "dbf").c_str());
     864             : 
     865             :     DBFHandle hDBF =
     866        1573 :         DBFCreateLL(pszFilename, (pszLDID != nullptr) ? pszLDID : "LDID/87",
     867        1573 :                     const_cast<SAHooks *>(VSI_SHP_GetHook(b2GBLimit)));
     868             : 
     869        1573 :     if (hDBF == nullptr)
     870             :     {
     871           1 :         CPLError(CE_Failure, CPLE_OpenFailed,
     872             :                  "Failed to create Shape DBF file `%s'.", pszFilename);
     873           1 :         CPLFree(pszFilename);
     874           1 :         CPLFree(pszFilenameWithoutExt);
     875           1 :         SHPClose(hSHP);
     876           1 :         return nullptr;
     877             :     }
     878             : 
     879        1572 :     CPLFree(pszFilename);
     880             : 
     881             :     /* -------------------------------------------------------------------- */
     882             :     /*      Create the .prj file, if required.                              */
     883             :     /* -------------------------------------------------------------------- */
     884        1572 :     std::string osPrjFilename;
     885        1572 :     OGRSpatialReference *poSRSClone = nullptr;
     886        1572 :     if (poSRS != nullptr)
     887             :     {
     888             :         osPrjFilename =
     889         160 :             CPLFormFilenameSafe(nullptr, pszFilenameWithoutExt, "prj");
     890         160 :         poSRSClone = poSRS->Clone();
     891             : 
     892         160 :         char *pszWKT = nullptr;
     893         160 :         VSILFILE *fp = nullptr;
     894         160 :         const char *const apszOptions[] = {"FORMAT=WKT1_ESRI", nullptr};
     895         316 :         if (poSRSClone->exportToWkt(&pszWKT, apszOptions) == OGRERR_NONE &&
     896         156 :             (fp = VSIFOpenL(osPrjFilename.c_str(), "wt")) != nullptr)
     897             :         {
     898         156 :             VSIFWriteL(pszWKT, strlen(pszWKT), 1, fp);
     899         156 :             VSIFCloseL(fp);
     900             :         }
     901             : 
     902         160 :         CPLFree(pszWKT);
     903             :     }
     904             : 
     905             :     /* -------------------------------------------------------------------- */
     906             :     /*      Create the layer object.                                        */
     907             :     /* -------------------------------------------------------------------- */
     908             :     // OGRShapeLayer constructor expects a filename with an extension (that
     909             :     // could be random actually), otherwise this is going to cause problems with
     910             :     // layer names that have a dot (not speaking about the one before the shp)
     911        1572 :     pszFilename = CPLStrdup(
     912        3144 :         CPLFormFilenameSafe(nullptr, pszFilenameWithoutExt, "shp").c_str());
     913             : 
     914             :     OGRShapeLayer *poLayer =
     915             :         new OGRShapeLayer(this, pszFilename, hSHP, hDBF, poSRSClone,
     916             :                           /* bSRSSet = */ true, osPrjFilename,
     917        1572 :                           /* bUpdate = */ true, eType);
     918        1572 :     if (poSRSClone != nullptr)
     919             :     {
     920         160 :         poSRSClone->Release();
     921             :     }
     922             : 
     923        1572 :     CPLFree(pszFilenameWithoutExt);
     924        1572 :     CPLFree(pszFilename);
     925             : 
     926        1572 :     poLayer->SetResizeAtClose(CPLFetchBool(papszOptions, "RESIZE", false));
     927        1572 :     poLayer->CreateSpatialIndexAtClose(
     928        1572 :         CPLFetchBool(papszOptions, "SPATIAL_INDEX", false));
     929        1572 :     poLayer->SetModificationDate(
     930             :         CSLFetchNameValue(papszOptions, "DBF_DATE_LAST_UPDATE"));
     931        1572 :     poLayer->SetAutoRepack(CPLFetchBool(papszOptions, "AUTO_REPACK", true));
     932        1572 :     poLayer->SetWriteDBFEOFChar(
     933        1572 :         CPLFetchBool(papszOptions, "DBF_EOF_CHAR", true));
     934             : 
     935             :     /* -------------------------------------------------------------------- */
     936             :     /*      Add layer to data source layer list.                            */
     937             :     /* -------------------------------------------------------------------- */
     938        1572 :     AddLayer(poLayer);
     939             : 
     940        1572 :     return poLayer;
     941             : }
     942             : 
     943             : /************************************************************************/
     944             : /*                           TestCapability()                           */
     945             : /************************************************************************/
     946             : 
     947         642 : int OGRShapeDataSource::TestCapability(const char *pszCap)
     948             : 
     949             : {
     950         642 :     if (EQUAL(pszCap, ODsCCreateLayer))
     951         322 :         return eAccess == GA_Update &&
     952         322 :                !(m_bIsZip && m_bSingleLayerZip && nLayers == 1);
     953         481 :     else if (EQUAL(pszCap, ODsCDeleteLayer))
     954          18 :         return eAccess == GA_Update && !(m_bIsZip && m_bSingleLayerZip);
     955         463 :     else if (EQUAL(pszCap, ODsCMeasuredGeometries))
     956           6 :         return true;
     957         457 :     else if (EQUAL(pszCap, ODsCZGeometries))
     958           6 :         return true;
     959         451 :     else if (EQUAL(pszCap, ODsCRandomLayerWrite))
     960           6 :         return eAccess == GA_Update;
     961             : 
     962         445 :     return false;
     963             : }
     964             : 
     965             : /************************************************************************/
     966             : /*                            GetLayerCount()                           */
     967             : /************************************************************************/
     968             : 
     969     1093710 : int OGRShapeDataSource::GetLayerCount()
     970             : 
     971             : {
     972             : #ifndef IMMEDIATE_OPENING
     973     1093710 :     if (!oVectorLayerName.empty())
     974             :     {
     975        1581 :         for (size_t i = 0; i < oVectorLayerName.size(); i++)
     976             :         {
     977        1484 :             const char *pszFilename = oVectorLayerName[i].c_str();
     978        1484 :             const std::string osLayerName = CPLGetBasenameSafe(pszFilename);
     979             : 
     980        1484 :             int j = 0;  // Used after for.
     981      253601 :             for (; j < nLayers; j++)
     982             :             {
     983      252625 :                 if (papoLayers[j]->GetName() == osLayerName)
     984         508 :                     break;
     985             :             }
     986        1484 :             if (j < nLayers)
     987         508 :                 continue;
     988             : 
     989         976 :             if (!OpenFile(pszFilename, eAccess == GA_Update))
     990             :             {
     991           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     992             :                          "Failed to open file %s."
     993             :                          "It may be corrupt or read-only file accessed in "
     994             :                          "update mode.",
     995             :                          pszFilename);
     996             :             }
     997             :         }
     998          97 :         oVectorLayerName.resize(0);
     999             :     }
    1000             : #endif
    1001             : 
    1002     1093710 :     return nLayers;
    1003             : }
    1004             : 
    1005             : /************************************************************************/
    1006             : /*                              GetLayer()                              */
    1007             : /************************************************************************/
    1008             : 
    1009      544267 : OGRLayer *OGRShapeDataSource::GetLayer(int iLayer)
    1010             : 
    1011             : {
    1012             :     // To ensure that existing layers are created.
    1013      544267 :     GetLayerCount();
    1014             : 
    1015      544267 :     if (iLayer < 0 || iLayer >= nLayers)
    1016           9 :         return nullptr;
    1017             : 
    1018      544258 :     return papoLayers[iLayer];
    1019             : }
    1020             : 
    1021             : /************************************************************************/
    1022             : /*                           GetLayerByName()                           */
    1023             : /************************************************************************/
    1024             : 
    1025        4955 : OGRLayer *OGRShapeDataSource::GetLayerByName(const char *pszLayerNameIn)
    1026             : {
    1027             : #ifndef IMMEDIATE_OPENING
    1028        4955 :     if (!oVectorLayerName.empty())
    1029             :     {
    1030      257268 :         for (int j = 0; j < nLayers; j++)
    1031             :         {
    1032      255928 :             if (strcmp(papoLayers[j]->GetName(), pszLayerNameIn) == 0)
    1033             :             {
    1034        1081 :                 return papoLayers[j];
    1035             :             }
    1036             :         }
    1037             : 
    1038        1440 :         for (int j = 0; j < 2; j++)
    1039             :         {
    1040      252180 :             for (size_t i = 0; i < oVectorLayerName.size(); i++)
    1041             :             {
    1042      252080 :                 const char *pszFilename = oVectorLayerName[i].c_str();
    1043      252080 :                 const std::string osLayerName = CPLGetBasenameSafe(pszFilename);
    1044             : 
    1045      252080 :                 if (j == 0)
    1046             :                 {
    1047      251970 :                     if (osLayerName != pszLayerNameIn)
    1048      250725 :                         continue;
    1049             :                 }
    1050             :                 else
    1051             :                 {
    1052         110 :                     if (!EQUAL(osLayerName.c_str(), pszLayerNameIn))
    1053          20 :                         continue;
    1054             :                 }
    1055             : 
    1056        1335 :                 if (!OpenFile(pszFilename, eAccess == GA_Update))
    1057             :                 {
    1058           1 :                     CPLError(CE_Failure, CPLE_OpenFailed,
    1059             :                              "Failed to open file %s.  "
    1060             :                              "It may be corrupt or read-only file accessed in "
    1061             :                              "update mode.",
    1062             :                              pszFilename);
    1063           1 :                     return nullptr;
    1064             :                 }
    1065             : 
    1066        1334 :                 return papoLayers[nLayers - 1];
    1067             :             }
    1068             :         }
    1069             : 
    1070           5 :         return nullptr;
    1071             :     }
    1072             : #endif
    1073             : 
    1074        2534 :     return GDALDataset::GetLayerByName(pszLayerNameIn);
    1075             : }
    1076             : 
    1077             : /************************************************************************/
    1078             : /*                             ExecuteSQL()                             */
    1079             : /*                                                                      */
    1080             : /*      We override this to provide special handling of CREATE          */
    1081             : /*      SPATIAL INDEX commands.  Support forms are:                     */
    1082             : /*                                                                      */
    1083             : /*        CREATE SPATIAL INDEX ON layer_name [DEPTH n]                  */
    1084             : /*        DROP SPATIAL INDEX ON layer_name                              */
    1085             : /*        REPACK layer_name                                             */
    1086             : /*        RECOMPUTE EXTENT ON layer_name                                */
    1087             : /************************************************************************/
    1088             : 
    1089         987 : OGRLayer *OGRShapeDataSource::ExecuteSQL(const char *pszStatement,
    1090             :                                          OGRGeometry *poSpatialFilter,
    1091             :                                          const char *pszDialect)
    1092             : 
    1093             : {
    1094         987 :     if (EQUAL(pszStatement, "UNCOMPRESS"))
    1095             :     {
    1096           0 :         CPL_IGNORE_RET_VAL(UncompressIfNeeded());
    1097           0 :         return nullptr;
    1098             :     }
    1099             : 
    1100         987 :     if (EQUAL(pszStatement, "RECOMPRESS"))
    1101             :     {
    1102           0 :         RecompressIfNeeded(GetLayerNames());
    1103           0 :         return nullptr;
    1104             :     }
    1105             :     /* ==================================================================== */
    1106             :     /*      Handle command to drop a spatial index.                         */
    1107             :     /* ==================================================================== */
    1108         987 :     if (STARTS_WITH_CI(pszStatement, "REPACK "))
    1109             :     {
    1110             :         OGRShapeLayer *poLayer =
    1111          17 :             cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 7));
    1112             : 
    1113          17 :         if (poLayer != nullptr)
    1114             :         {
    1115          17 :             if (poLayer->Repack() != OGRERR_NONE)
    1116             :             {
    1117           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1118             :                          "REPACK of layer '%s' failed.", pszStatement + 7);
    1119             :             }
    1120             :         }
    1121             :         else
    1122             :         {
    1123           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1124             :                      "No such layer as '%s' in REPACK.", pszStatement + 7);
    1125             :         }
    1126          17 :         return nullptr;
    1127             :     }
    1128             : 
    1129             :     /* ==================================================================== */
    1130             :     /*      Handle command to shrink columns to their minimum size.         */
    1131             :     /* ==================================================================== */
    1132         970 :     if (STARTS_WITH_CI(pszStatement, "RESIZE "))
    1133             :     {
    1134             :         OGRShapeLayer *poLayer =
    1135           1 :             cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 7));
    1136             : 
    1137           1 :         if (poLayer != nullptr)
    1138             :         {
    1139           1 :             poLayer->ResizeDBF();
    1140             :         }
    1141             :         else
    1142             :         {
    1143           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1144             :                      "No such layer as '%s' in RESIZE.", pszStatement + 7);
    1145             :         }
    1146           1 :         return nullptr;
    1147             :     }
    1148             : 
    1149             :     /* ==================================================================== */
    1150             :     /*      Handle command to recompute extent                             */
    1151             :     /* ==================================================================== */
    1152         969 :     if (STARTS_WITH_CI(pszStatement, "RECOMPUTE EXTENT ON "))
    1153             :     {
    1154             :         OGRShapeLayer *poLayer =
    1155           6 :             cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 20));
    1156             : 
    1157           6 :         if (poLayer != nullptr)
    1158             :         {
    1159           5 :             poLayer->RecomputeExtent();
    1160             :         }
    1161             :         else
    1162             :         {
    1163           1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1164             :                      "No such layer as '%s' in RECOMPUTE EXTENT.",
    1165             :                      pszStatement + 20);
    1166             :         }
    1167           6 :         return nullptr;
    1168             :     }
    1169             : 
    1170             :     /* ==================================================================== */
    1171             :     /*      Handle command to drop a spatial index.                         */
    1172             :     /* ==================================================================== */
    1173         963 :     if (STARTS_WITH_CI(pszStatement, "DROP SPATIAL INDEX ON "))
    1174             :     {
    1175             :         OGRShapeLayer *poLayer =
    1176           3 :             cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 22));
    1177             : 
    1178           3 :         if (poLayer != nullptr)
    1179             :         {
    1180           3 :             poLayer->DropSpatialIndex();
    1181             :         }
    1182             :         else
    1183             :         {
    1184           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1185             :                      "No such layer as '%s' in DROP SPATIAL INDEX.",
    1186             :                      pszStatement + 22);
    1187             :         }
    1188           3 :         return nullptr;
    1189             :     }
    1190             : 
    1191             :     /* ==================================================================== */
    1192             :     /*      Handle all commands except spatial index creation generically.  */
    1193             :     /* ==================================================================== */
    1194         960 :     if (!STARTS_WITH_CI(pszStatement, "CREATE SPATIAL INDEX ON "))
    1195             :     {
    1196         944 :         char **papszTokens = CSLTokenizeString(pszStatement);
    1197         944 :         if (CSLCount(papszTokens) >= 4 &&
    1198         440 :             (EQUAL(papszTokens[0], "CREATE") ||
    1199         412 :              EQUAL(papszTokens[0], "DROP")) &&
    1200        1384 :             EQUAL(papszTokens[1], "INDEX") && EQUAL(papszTokens[2], "ON"))
    1201             :         {
    1202             :             OGRShapeLayer *poLayer =
    1203          38 :                 cpl::down_cast<OGRShapeLayer *>(GetLayerByName(papszTokens[3]));
    1204          38 :             if (poLayer != nullptr)
    1205          38 :                 poLayer->InitializeIndexSupport(poLayer->GetFullName());
    1206             :         }
    1207         944 :         CSLDestroy(papszTokens);
    1208             : 
    1209         944 :         return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter,
    1210         944 :                                        pszDialect);
    1211             :     }
    1212             : 
    1213             :     /* -------------------------------------------------------------------- */
    1214             :     /*      Parse into keywords.                                            */
    1215             :     /* -------------------------------------------------------------------- */
    1216          16 :     char **papszTokens = CSLTokenizeString(pszStatement);
    1217             : 
    1218          32 :     if (CSLCount(papszTokens) < 5 || !EQUAL(papszTokens[0], "CREATE") ||
    1219          16 :         !EQUAL(papszTokens[1], "SPATIAL") || !EQUAL(papszTokens[2], "INDEX") ||
    1220          48 :         !EQUAL(papszTokens[3], "ON") || CSLCount(papszTokens) > 7 ||
    1221          16 :         (CSLCount(papszTokens) == 7 && !EQUAL(papszTokens[5], "DEPTH")))
    1222             :     {
    1223           0 :         CSLDestroy(papszTokens);
    1224           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1225             :                  "Syntax error in CREATE SPATIAL INDEX command.\n"
    1226             :                  "Was '%s'\n"
    1227             :                  "Should be of form 'CREATE SPATIAL INDEX ON <table> "
    1228             :                  "[DEPTH <n>]'",
    1229             :                  pszStatement);
    1230           0 :         return nullptr;
    1231             :     }
    1232             : 
    1233             :     /* -------------------------------------------------------------------- */
    1234             :     /*      Get depth if provided.                                          */
    1235             :     /* -------------------------------------------------------------------- */
    1236          16 :     const int nDepth = CSLCount(papszTokens) == 7 ? atoi(papszTokens[6]) : 0;
    1237             : 
    1238             :     /* -------------------------------------------------------------------- */
    1239             :     /*      What layer are we operating on.                                 */
    1240             :     /* -------------------------------------------------------------------- */
    1241             :     OGRShapeLayer *poLayer =
    1242          16 :         cpl::down_cast<OGRShapeLayer *>(GetLayerByName(papszTokens[4]));
    1243             : 
    1244          16 :     if (poLayer == nullptr)
    1245             :     {
    1246           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Layer %s not recognised.",
    1247           0 :                  papszTokens[4]);
    1248           0 :         CSLDestroy(papszTokens);
    1249           0 :         return nullptr;
    1250             :     }
    1251             : 
    1252          16 :     CSLDestroy(papszTokens);
    1253             : 
    1254          16 :     poLayer->CreateSpatialIndex(nDepth);
    1255          16 :     return nullptr;
    1256             : }
    1257             : 
    1258             : /************************************************************************/
    1259             : /*                     GetExtensionsForDeletion()                       */
    1260             : /************************************************************************/
    1261             : 
    1262         686 : const char *const *OGRShapeDataSource::GetExtensionsForDeletion()
    1263             : {
    1264             :     static const char *const apszExtensions[] = {
    1265             :         "shp",  "shx", "dbf", "sbn", "sbx", "prj", "idm", "ind", "qix", "cpg",
    1266             :         "qpj",  // QGIS projection file
    1267             :         nullptr};
    1268         686 :     return apszExtensions;
    1269             : }
    1270             : 
    1271             : /************************************************************************/
    1272             : /*                            DeleteLayer()                             */
    1273             : /************************************************************************/
    1274             : 
    1275         543 : OGRErr OGRShapeDataSource::DeleteLayer(int iLayer)
    1276             : 
    1277             : {
    1278             :     /* -------------------------------------------------------------------- */
    1279             :     /*      Verify we are in update mode.                                   */
    1280             :     /* -------------------------------------------------------------------- */
    1281         543 :     if (eAccess != GA_Update)
    1282             :     {
    1283           1 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1284             :                  "Data source %s opened read-only.  "
    1285             :                  "Layer %d cannot be deleted.",
    1286           1 :                  GetDescription(), iLayer);
    1287             : 
    1288           1 :         return OGRERR_FAILURE;
    1289             :     }
    1290             : 
    1291             :     // To ensure that existing layers are created.
    1292         542 :     GetLayerCount();
    1293             : 
    1294         542 :     if (iLayer < 0 || iLayer >= nLayers)
    1295             :     {
    1296           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    1297             :                  "Layer %d not in legal range of 0 to %d.", iLayer,
    1298           2 :                  nLayers - 1);
    1299           2 :         return OGRERR_FAILURE;
    1300             :     }
    1301             : 
    1302         540 :     if (m_bIsZip && m_bSingleLayerZip)
    1303             :     {
    1304           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1305             :                  ".shz does not support layer deletion");
    1306           1 :         return OGRERR_FAILURE;
    1307             :     }
    1308             : 
    1309         539 :     if (!UncompressIfNeeded())
    1310           0 :         return OGRERR_FAILURE;
    1311             : 
    1312         539 :     OGRShapeLayer *poLayerToDelete = papoLayers[iLayer];
    1313             : 
    1314         539 :     char *const pszFilename = CPLStrdup(poLayerToDelete->GetFullName());
    1315             : 
    1316         539 :     delete poLayerToDelete;
    1317             : 
    1318       86505 :     while (iLayer < nLayers - 1)
    1319             :     {
    1320       85966 :         papoLayers[iLayer] = papoLayers[iLayer + 1];
    1321       85966 :         iLayer++;
    1322             :     }
    1323             : 
    1324         539 :     nLayers--;
    1325             : 
    1326             :     const char *const *papszExtensions =
    1327         539 :         OGRShapeDataSource::GetExtensionsForDeletion();
    1328        6468 :     for (int iExt = 0; papszExtensions[iExt] != nullptr; iExt++)
    1329             :     {
    1330             :         const std::string osFile =
    1331       11858 :             CPLResetExtensionSafe(pszFilename, papszExtensions[iExt]);
    1332             :         VSIStatBufL sStatBuf;
    1333        5929 :         if (VSIStatL(osFile.c_str(), &sStatBuf) == 0)
    1334        1609 :             VSIUnlink(osFile.c_str());
    1335             :     }
    1336             : 
    1337         539 :     CPLFree(pszFilename);
    1338             : 
    1339         539 :     return OGRERR_NONE;
    1340             : }
    1341             : 
    1342             : /************************************************************************/
    1343             : /*                          SetLastUsedLayer()                          */
    1344             : /************************************************************************/
    1345             : 
    1346      217517 : void OGRShapeDataSource::SetLastUsedLayer(OGRShapeLayer *poLayer)
    1347             : {
    1348             :     // We could remove that check and things would still work in
    1349             :     // 99.99% cases.
    1350             :     // The only rationale for that test is to avoid breaking applications that
    1351             :     // would deal with layers of the same datasource in different threads. In
    1352             :     // GDAL < 1.9.0, this would work in most cases I can imagine as shapefile
    1353             :     // layers are pretty much independent from each others (although it has
    1354             :     // never been guaranteed to be a valid use case, and the shape driver is
    1355             :     // likely more the exception than the rule in permitting accessing layers
    1356             :     // from different threads !)  Anyway the LRU list mechanism leaves the door
    1357             :     // open to concurrent accesses to it so when the datasource has not many
    1358             :     // layers, we don't try to build the LRU list to avoid concurrency issues. I
    1359             :     // haven't bothered making the analysis of how a mutex could be used to
    1360             :     // protect that (my intuition is that it would need to be placed at the
    1361             :     // beginning of OGRShapeLayer::TouchLayer() ).
    1362      217517 :     if (nLayers < poPool->GetMaxSimultaneouslyOpened())
    1363      208675 :         return;
    1364             : 
    1365        8842 :     poPool->SetLastUsedLayer(poLayer);
    1366             : }
    1367             : 
    1368             : /************************************************************************/
    1369             : //                            GetFileList()                             */
    1370             : /************************************************************************/
    1371             : 
    1372          29 : char **OGRShapeDataSource::GetFileList()
    1373             : {
    1374          29 :     if (m_bIsZip)
    1375             :     {
    1376           1 :         return CSLAddString(nullptr, GetDescription());
    1377             :     }
    1378          56 :     CPLStringList oFileList;
    1379          28 :     GetLayerCount();
    1380         163 :     for (int i = 0; i < nLayers; i++)
    1381             :     {
    1382         135 :         OGRShapeLayer *poLayer = papoLayers[i];
    1383         135 :         poLayer->AddToFileList(oFileList);
    1384             :     }
    1385          28 :     return oFileList.StealList();
    1386             : }
    1387             : 
    1388             : /************************************************************************/
    1389             : //                          RefreshLockFile()                            */
    1390             : /************************************************************************/
    1391             : 
    1392           0 : void OGRShapeDataSource::RefreshLockFile(void *_self)
    1393             : {
    1394           0 :     OGRShapeDataSource *self = static_cast<OGRShapeDataSource *>(_self);
    1395           0 :     CPLAssert(self->m_psLockFile);
    1396           0 :     CPLAcquireMutex(self->m_poRefreshLockFileMutex, 1000);
    1397           0 :     self->m_bRefreshLockFileThreadStarted = true;
    1398           0 :     CPLCondSignal(self->m_poRefreshLockFileCond);
    1399           0 :     unsigned int nInc = 0;
    1400           0 :     while (!(self->m_bExitRefreshLockFileThread))
    1401             :     {
    1402           0 :         auto ret = CPLCondTimedWait(self->m_poRefreshLockFileCond,
    1403             :                                     self->m_poRefreshLockFileMutex,
    1404             :                                     self->m_dfRefreshLockDelay);
    1405           0 :         if (ret == COND_TIMED_WAIT_TIME_OUT)
    1406             :         {
    1407           0 :             CPLAssert(self->m_psLockFile);
    1408           0 :             VSIFSeekL(self->m_psLockFile, 0, SEEK_SET);
    1409           0 :             CPLString osTime;
    1410           0 :             nInc++;
    1411             :             osTime.Printf(CPL_FRMT_GUIB ", %u\n",
    1412           0 :                           static_cast<GUIntBig>(time(nullptr)), nInc);
    1413           0 :             VSIFWriteL(osTime.data(), 1, osTime.size(), self->m_psLockFile);
    1414           0 :             VSIFFlushL(self->m_psLockFile);
    1415             :         }
    1416             :     }
    1417           0 :     CPLReleaseMutex(self->m_poRefreshLockFileMutex);
    1418           0 : }
    1419             : 
    1420             : /************************************************************************/
    1421             : //                            RemoveLockFile()                          */
    1422             : /************************************************************************/
    1423             : 
    1424        2716 : void OGRShapeDataSource::RemoveLockFile()
    1425             : {
    1426        2716 :     if (!m_psLockFile)
    1427        2716 :         return;
    1428             : 
    1429             :     // Ask the thread to terminate
    1430           0 :     CPLAcquireMutex(m_poRefreshLockFileMutex, 1000);
    1431           0 :     m_bExitRefreshLockFileThread = true;
    1432           0 :     CPLCondSignal(m_poRefreshLockFileCond);
    1433           0 :     CPLReleaseMutex(m_poRefreshLockFileMutex);
    1434           0 :     CPLJoinThread(m_hRefreshLockFileThread);
    1435           0 :     m_hRefreshLockFileThread = nullptr;
    1436             : 
    1437             :     // Close and remove lock file
    1438           0 :     VSIFCloseL(m_psLockFile);
    1439           0 :     m_psLockFile = nullptr;
    1440           0 :     CPLString osLockFile(GetDescription());
    1441           0 :     osLockFile += ".gdal.lock";
    1442           0 :     VSIUnlink(osLockFile);
    1443             : }
    1444             : 
    1445             : /************************************************************************/
    1446             : //                         UncompressIfNeeded()                         */
    1447             : /************************************************************************/
    1448             : 
    1449       71090 : bool OGRShapeDataSource::UncompressIfNeeded()
    1450             : {
    1451       71090 :     if (eAccess != GA_Update || !m_bIsZip || !m_osTemporaryUnzipDir.empty())
    1452       71085 :         return true;
    1453             : 
    1454           5 :     GetLayerCount();
    1455             : 
    1456           0 :     auto returnError = [this]()
    1457             :     {
    1458           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot uncompress %s",
    1459           0 :                  GetDescription());
    1460           0 :         return false;
    1461           5 :     };
    1462             : 
    1463           5 :     if (nLayers > 1)
    1464             :     {
    1465           0 :         CPLString osLockFile(GetDescription());
    1466           0 :         osLockFile += ".gdal.lock";
    1467             :         VSIStatBufL sStat;
    1468           0 :         if (VSIStatL(osLockFile, &sStat) == 0 &&
    1469           0 :             sStat.st_mtime > time(nullptr) - 2 * knREFRESH_LOCK_FILE_DELAY_SEC)
    1470             :         {
    1471           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1472             :                      "Cannot edit %s. Another task is editing it",
    1473           0 :                      GetDescription());
    1474           0 :             return false;
    1475             :         }
    1476           0 :         if (!m_poRefreshLockFileMutex)
    1477             :         {
    1478           0 :             m_poRefreshLockFileMutex = CPLCreateMutex();
    1479           0 :             if (!m_poRefreshLockFileMutex)
    1480           0 :                 return false;
    1481           0 :             CPLReleaseMutex(m_poRefreshLockFileMutex);
    1482             :         }
    1483           0 :         if (!m_poRefreshLockFileCond)
    1484             :         {
    1485           0 :             m_poRefreshLockFileCond = CPLCreateCond();
    1486           0 :             if (!m_poRefreshLockFileCond)
    1487           0 :                 return false;
    1488             :         }
    1489           0 :         auto f = VSIFOpenL(osLockFile, "wb");
    1490           0 :         if (!f)
    1491             :         {
    1492           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot create lock file");
    1493           0 :             return false;
    1494             :         }
    1495           0 :         m_psLockFile = f;
    1496           0 :         CPLAcquireMutex(m_poRefreshLockFileMutex, 1000);
    1497           0 :         m_bExitRefreshLockFileThread = false;
    1498           0 :         m_bRefreshLockFileThreadStarted = false;
    1499           0 :         CPLReleaseMutex(m_poRefreshLockFileMutex);
    1500             :         // Config option mostly for testing purposes
    1501             :         // coverity[tainted_data]
    1502           0 :         m_dfRefreshLockDelay = CPLAtof(CPLGetConfigOption(
    1503             :             "OGR_SHAPE_LOCK_DELAY",
    1504             :             CPLSPrintf("%d", knREFRESH_LOCK_FILE_DELAY_SEC)));
    1505           0 :         m_hRefreshLockFileThread =
    1506           0 :             CPLCreateJoinableThread(OGRShapeDataSource::RefreshLockFile, this);
    1507           0 :         if (!m_hRefreshLockFileThread)
    1508             :         {
    1509           0 :             VSIFCloseL(m_psLockFile);
    1510           0 :             m_psLockFile = nullptr;
    1511           0 :             VSIUnlink(osLockFile);
    1512             :         }
    1513             :         else
    1514             :         {
    1515           0 :             CPLAcquireMutex(m_poRefreshLockFileMutex, 1000);
    1516           0 :             while (!m_bRefreshLockFileThreadStarted)
    1517             :             {
    1518           0 :                 CPLCondWait(m_poRefreshLockFileCond, m_poRefreshLockFileMutex);
    1519             :             }
    1520           0 :             CPLReleaseMutex(m_poRefreshLockFileMutex);
    1521             :         }
    1522             :     }
    1523             : 
    1524          10 :     CPLString osVSIZipDirname(GetVSIZipPrefixeDir());
    1525           5 :     vsi_l_offset nTotalUncompressedSize = 0;
    1526          10 :     CPLStringList aosFiles(VSIReadDir(osVSIZipDirname));
    1527          19 :     for (int i = 0; i < aosFiles.size(); i++)
    1528             :     {
    1529          14 :         const char *pszFilename = aosFiles[i];
    1530          14 :         if (!EQUAL(pszFilename, ".") && !EQUAL(pszFilename, ".."))
    1531             :         {
    1532             :             const CPLString osSrcFile(
    1533          28 :                 CPLFormFilenameSafe(osVSIZipDirname, pszFilename, nullptr));
    1534             :             VSIStatBufL sStat;
    1535          14 :             if (VSIStatL(osSrcFile, &sStat) == 0)
    1536             :             {
    1537          14 :                 nTotalUncompressedSize += sStat.st_size;
    1538             :             }
    1539             :         }
    1540             :     }
    1541             : 
    1542          10 :     CPLString osTemporaryDir(GetDescription());
    1543           5 :     osTemporaryDir += "_tmp_uncompressed";
    1544             : 
    1545             :     const char *pszUseVsimem =
    1546           5 :         CPLGetConfigOption("OGR_SHAPE_USE_VSIMEM_FOR_TEMP", "AUTO");
    1547          10 :     if (EQUAL(pszUseVsimem, "YES") ||
    1548           5 :         (EQUAL(pszUseVsimem, "AUTO") && nTotalUncompressedSize > 0 &&
    1549             :          nTotalUncompressedSize <
    1550           3 :              static_cast<GUIntBig>(CPLGetUsablePhysicalRAM() / 10)))
    1551             :     {
    1552           3 :         osTemporaryDir = VSIMemGenerateHiddenFilename("shapedriver");
    1553             :     }
    1554           5 :     CPLDebug("Shape", "Uncompressing to %s", osTemporaryDir.c_str());
    1555             : 
    1556           5 :     VSIRmdirRecursive(osTemporaryDir);
    1557           5 :     if (VSIMkdir(osTemporaryDir, 0755) != 0)
    1558           0 :         return returnError();
    1559          19 :     for (int i = 0; i < aosFiles.size(); i++)
    1560             :     {
    1561          14 :         const char *pszFilename = aosFiles[i];
    1562          14 :         if (!EQUAL(pszFilename, ".") && !EQUAL(pszFilename, ".."))
    1563             :         {
    1564             :             const CPLString osSrcFile(
    1565          14 :                 CPLFormFilenameSafe(osVSIZipDirname, pszFilename, nullptr));
    1566             :             const CPLString osDestFile(
    1567          14 :                 CPLFormFilenameSafe(osTemporaryDir, pszFilename, nullptr));
    1568          14 :             if (CPLCopyFile(osDestFile, osSrcFile) != 0)
    1569             :             {
    1570           0 :                 VSIRmdirRecursive(osTemporaryDir);
    1571           0 :                 return returnError();
    1572             :             }
    1573             :         }
    1574             :     }
    1575             : 
    1576           5 :     m_osTemporaryUnzipDir = std::move(osTemporaryDir);
    1577             : 
    1578           8 :     for (int i = 0; i < nLayers; i++)
    1579             :     {
    1580           3 :         OGRShapeLayer *poLayer = papoLayers[i];
    1581           3 :         poLayer->UpdateFollowingDeOrRecompression();
    1582             :     }
    1583             : 
    1584           5 :     return true;
    1585             : }
    1586             : 
    1587             : /************************************************************************/
    1588             : //                         RecompressIfNeeded()                         */
    1589             : /************************************************************************/
    1590             : 
    1591        2711 : bool OGRShapeDataSource::RecompressIfNeeded(
    1592             :     const std::vector<CPLString> &layerNames)
    1593             : {
    1594        2711 :     if (eAccess != GA_Update || !m_bIsZip || m_osTemporaryUnzipDir.empty())
    1595        2706 :         return true;
    1596             : 
    1597           0 :     auto returnError = [this]()
    1598             :     {
    1599           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot recompress %s",
    1600           0 :                  GetDescription());
    1601           0 :         RemoveLockFile();
    1602           0 :         return false;
    1603           5 :     };
    1604             : 
    1605          10 :     CPLStringList aosFiles(VSIReadDir(m_osTemporaryUnzipDir));
    1606          10 :     CPLString osTmpZip(m_osTemporaryUnzipDir + ".zip");
    1607           5 :     VSIUnlink(osTmpZip);
    1608          15 :     CPLString osTmpZipWithVSIZip("/vsizip/{" + osTmpZip + '}');
    1609             : 
    1610          10 :     std::map<CPLString, int> oMapLayerOrder;
    1611          10 :     for (size_t i = 0; i < layerNames.size(); i++)
    1612           5 :         oMapLayerOrder[layerNames[i]] = static_cast<int>(i);
    1613             : 
    1614          10 :     std::vector<CPLString> sortedFiles;
    1615           5 :     vsi_l_offset nTotalUncompressedSize = 0;
    1616          31 :     for (int i = 0; i < aosFiles.size(); i++)
    1617             :     {
    1618          26 :         sortedFiles.emplace_back(aosFiles[i]);
    1619             :         const CPLString osSrcFile(
    1620          52 :             CPLFormFilenameSafe(m_osTemporaryUnzipDir, aosFiles[i], nullptr));
    1621             :         VSIStatBufL sStat;
    1622          26 :         if (VSIStatL(osSrcFile, &sStat) == 0)
    1623             :         {
    1624          26 :             nTotalUncompressedSize += sStat.st_size;
    1625             :         }
    1626             :     }
    1627             : 
    1628             :     // Sort files by their layer orders, and then for files of the same layer,
    1629             :     // make shp appear first, and then by filename order
    1630           5 :     std::sort(sortedFiles.begin(), sortedFiles.end(),
    1631         180 :               [&oMapLayerOrder](const CPLString &a, const CPLString &b)
    1632             :               {
    1633          45 :                   int iA = INT_MAX;
    1634             :                   auto oIterA =
    1635          45 :                       oMapLayerOrder.find(CPLGetBasenameSafe(a).c_str());
    1636          45 :                   if (oIterA != oMapLayerOrder.end())
    1637          35 :                       iA = oIterA->second;
    1638          45 :                   int iB = INT_MAX;
    1639             :                   auto oIterB =
    1640          45 :                       oMapLayerOrder.find(CPLGetBasenameSafe(b).c_str());
    1641          45 :                   if (oIterB != oMapLayerOrder.end())
    1642          37 :                       iB = oIterB->second;
    1643          45 :                   if (iA < iB)
    1644           6 :                       return true;
    1645          39 :                   if (iA > iB)
    1646           8 :                       return false;
    1647          31 :                   if (iA != INT_MAX)
    1648             :                   {
    1649          29 :                       if (EQUAL(CPLGetExtensionSafe(a).c_str(), "shp"))
    1650           4 :                           return true;
    1651          25 :                       if (EQUAL(CPLGetExtensionSafe(b).c_str(), "shp"))
    1652          10 :                           return false;
    1653             :                   }
    1654          17 :                   return a < b;
    1655             :               });
    1656             : 
    1657             :     CPLConfigOptionSetter oZIP64Setter(
    1658             :         "CPL_CREATE_ZIP64",
    1659          10 :         nTotalUncompressedSize < 4000U * 1000 * 1000 ? "NO" : "YES", true);
    1660             : 
    1661             :     /* Maintain a handle on the ZIP opened */
    1662           5 :     VSILFILE *fpZIP = VSIFOpenExL(osTmpZipWithVSIZip, "wb", true);
    1663           5 :     if (fpZIP == nullptr)
    1664             :     {
    1665           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s: %s",
    1666             :                  osTmpZipWithVSIZip.c_str(), VSIGetLastErrorMsg());
    1667           0 :         return returnError();
    1668             :     }
    1669             : 
    1670          31 :     for (const auto &osFilename : sortedFiles)
    1671             :     {
    1672          26 :         const char *pszFilename = osFilename.c_str();
    1673          26 :         if (!EQUAL(pszFilename, ".") && !EQUAL(pszFilename, ".."))
    1674             :         {
    1675          22 :             const CPLString osSrcFile(CPLFormFilenameSafe(
    1676          22 :                 m_osTemporaryUnzipDir, pszFilename, nullptr));
    1677             :             const CPLString osDestFile(
    1678          22 :                 CPLFormFilenameSafe(osTmpZipWithVSIZip, pszFilename, nullptr));
    1679          22 :             if (CPLCopyFile(osDestFile, osSrcFile) != 0)
    1680             :             {
    1681           0 :                 VSIFCloseL(fpZIP);
    1682           0 :                 return returnError();
    1683             :             }
    1684             :         }
    1685             :     }
    1686             : 
    1687           5 :     VSIFCloseL(fpZIP);
    1688             : 
    1689             :     const bool bOverwrite =
    1690           5 :         CPLTestBool(CPLGetConfigOption("OGR_SHAPE_PACK_IN_PLACE",
    1691             : #ifdef _WIN32
    1692             :                                        "YES"
    1693             : #else
    1694             :                                        "NO"
    1695             : #endif
    1696             :                                        ));
    1697           5 :     if (bOverwrite)
    1698             :     {
    1699           0 :         VSILFILE *fpTarget = nullptr;
    1700           0 :         for (int i = 0; i < 10; i++)
    1701             :         {
    1702           0 :             fpTarget = VSIFOpenL(GetDescription(), "rb+");
    1703           0 :             if (fpTarget)
    1704           0 :                 break;
    1705           0 :             CPLSleep(0.1);
    1706             :         }
    1707           0 :         if (!fpTarget)
    1708           0 :             return returnError();
    1709           0 :         bool bCopyOK = CopyInPlace(fpTarget, osTmpZip);
    1710           0 :         VSIFCloseL(fpTarget);
    1711           0 :         VSIUnlink(osTmpZip);
    1712           0 :         if (!bCopyOK)
    1713             :         {
    1714           0 :             return returnError();
    1715             :         }
    1716             :     }
    1717             :     else
    1718             :     {
    1719          10 :         if (VSIUnlink(GetDescription()) != 0 ||
    1720           5 :             CPLMoveFile(GetDescription(), osTmpZip) != 0)
    1721             :         {
    1722           0 :             return returnError();
    1723             :         }
    1724             :     }
    1725             : 
    1726           5 :     VSIRmdirRecursive(m_osTemporaryUnzipDir);
    1727           5 :     m_osTemporaryUnzipDir.clear();
    1728             : 
    1729           5 :     for (int i = 0; i < nLayers; i++)
    1730             :     {
    1731           0 :         OGRShapeLayer *poLayer = papoLayers[i];
    1732           0 :         poLayer->UpdateFollowingDeOrRecompression();
    1733             :     }
    1734             : 
    1735           5 :     RemoveLockFile();
    1736             : 
    1737           5 :     return true;
    1738             : }
    1739             : 
    1740             : /************************************************************************/
    1741             : /*                            CopyInPlace()                             */
    1742             : /************************************************************************/
    1743             : 
    1744           3 : bool OGRShapeDataSource::CopyInPlace(VSILFILE *fpTarget,
    1745             :                                      const CPLString &osSourceFilename)
    1746             : {
    1747           3 :     return CPL_TO_BOOL(VSIOverwriteFile(fpTarget, osSourceFilename.c_str()));
    1748             : }

Generated by: LCOV version 1.14