LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - ogrshapedatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 598 747 80.1 %
Date: 2025-09-10 17:48:50 Functions: 28 31 90.3 %

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

Generated by: LCOV version 1.14