LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - ogrshapelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1502 1936 77.6 %
Date: 2025-12-10 05:42:13 Functions: 54 54 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRShapeLayer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
       9             :  * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogrshape.h"
      15             : 
      16             : #include <cerrno>
      17             : #include <limits>
      18             : #include <cmath>
      19             : #include <cstddef>
      20             : #include <cstdio>
      21             : #include <cstdlib>
      22             : #include <cstring>
      23             : #include <ctime>
      24             : #include <algorithm>
      25             : #include <string>
      26             : 
      27             : #include "cpl_conv.h"
      28             : #include "cpl_error.h"
      29             : #include "cpl_multiproc.h"
      30             : #include "cpl_port.h"
      31             : #include "cpl_string.h"
      32             : #include "cpl_time.h"
      33             : #include "cpl_vsi.h"
      34             : #include "cpl_vsi_virtual.h"
      35             : #include "ogr_core.h"
      36             : #include "ogr_feature.h"
      37             : #include "ogr_geometry.h"
      38             : #include "ogr_p.h"
      39             : #include "ogr_spatialref.h"
      40             : #include "ogr_srs_api.h"
      41             : #include "ogrlayerpool.h"
      42             : #include "ograrrowarrayhelper.h"
      43             : #include "ogrsf_frmts.h"
      44             : #include "shapefil.h"
      45             : #include "shp_vsi.h"
      46             : 
      47             : /************************************************************************/
      48             : /*                           OGRShapeLayer()                            */
      49             : /************************************************************************/
      50             : 
      51        7739 : OGRShapeLayer::OGRShapeLayer(OGRShapeDataSource *poDSIn,
      52             :                              const char *pszFullNameIn, SHPHandle hSHPIn,
      53             :                              DBFHandle hDBFIn,
      54             :                              const OGRSpatialReference *poSRSIn, bool bSRSSetIn,
      55             :                              const std::string &osPrjFilename, bool bUpdate,
      56             :                              OGRwkbGeometryType eReqType,
      57        7739 :                              CSLConstList papszCreateOptions)
      58             :     : OGRAbstractProxiedLayer(poDSIn->GetPool()), m_poDS(poDSIn),
      59             :       m_osFullName(pszFullNameIn), m_hSHP(hSHPIn), m_hDBF(hDBFIn),
      60             :       m_bUpdateAccess(bUpdate), m_eRequestedGeomType(eReqType),
      61        7739 :       m_bHSHPWasNonNULL(hSHPIn != nullptr), m_bHDBFWasNonNULL(hDBFIn != nullptr)
      62             : {
      63        7739 :     if (m_hSHP != nullptr)
      64             :     {
      65        6951 :         m_nTotalShapeCount = m_hSHP->nRecords;
      66        6951 :         if (m_hDBF != nullptr && m_hDBF->nRecords != m_nTotalShapeCount)
      67             :         {
      68           0 :             CPLDebug("Shape",
      69             :                      "Inconsistent record number in .shp (%d) and in .dbf (%d)",
      70           0 :                      m_hSHP->nRecords, m_hDBF->nRecords);
      71             :         }
      72             :     }
      73         788 :     else if (m_hDBF != nullptr)
      74             :     {
      75         788 :         m_nTotalShapeCount = m_hDBF->nRecords;
      76             :     }
      77             : #ifdef DEBUG
      78             :     else
      79             :     {
      80           0 :         CPLError(CE_Fatal, CPLE_AssertionFailed,
      81             :                  "Should not happen: Both m_hSHP and m_hDBF are nullptrs");
      82             :     }
      83             : #endif
      84             : 
      85        7739 :     if (!TouchLayer())
      86             :     {
      87           0 :         CPLDebug("Shape", "TouchLayer in shape ctor failed. ");
      88             :     }
      89             : 
      90        7739 :     if (m_hDBF != nullptr && m_hDBF->pszCodePage != nullptr)
      91             :     {
      92        6356 :         CPLDebug("Shape", "DBF Codepage = %s for %s", m_hDBF->pszCodePage,
      93             :                  m_osFullName.c_str());
      94             : 
      95             :         // Not too sure about this, but it seems like better than nothing.
      96        6356 :         m_osEncoding = ConvertCodePage(m_hDBF->pszCodePage);
      97             :     }
      98             : 
      99        7739 :     if (m_hDBF != nullptr)
     100             :     {
     101        7679 :         if (!(m_hDBF->nUpdateYearSince1900 == 95 && m_hDBF->nUpdateMonth == 7 &&
     102        2314 :               m_hDBF->nUpdateDay == 26))
     103             :         {
     104        5365 :             SetMetadataItem("DBF_DATE_LAST_UPDATE",
     105             :                             CPLSPrintf("%04d-%02d-%02d",
     106        5365 :                                        m_hDBF->nUpdateYearSince1900 + 1900,
     107        5365 :                                        m_hDBF->nUpdateMonth,
     108        5365 :                                        m_hDBF->nUpdateDay));
     109             :         }
     110             :         struct tm tm;
     111        7679 :         CPLUnixTimeToYMDHMS(time(nullptr), &tm);
     112        7679 :         DBFSetLastModifiedDate(m_hDBF, tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
     113             :     }
     114             : 
     115             :     const char *pszShapeEncoding =
     116        7739 :         CSLFetchNameValue(m_poDS->GetOpenOptions(), "ENCODING");
     117        7739 :     if (pszShapeEncoding == nullptr && m_osEncoding == "")
     118        1383 :         pszShapeEncoding = CSLFetchNameValue(papszCreateOptions, "ENCODING");
     119        7739 :     if (pszShapeEncoding == nullptr)
     120        7738 :         pszShapeEncoding = CPLGetConfigOption("SHAPE_ENCODING", nullptr);
     121        7739 :     if (pszShapeEncoding != nullptr)
     122           1 :         m_osEncoding = pszShapeEncoding;
     123             : 
     124        7739 :     if (m_osEncoding != "")
     125             :     {
     126        6355 :         CPLDebug("Shape", "Treating as encoding '%s'.", m_osEncoding.c_str());
     127             : 
     128        6355 :         if (!OGRShapeLayer::TestCapability(OLCStringsAsUTF8))
     129             :         {
     130           1 :             CPLDebug("Shape", "Cannot recode from '%s'. Disabling recoding",
     131             :                      m_osEncoding.c_str());
     132           1 :             m_osEncoding = "";
     133             :         }
     134             :     }
     135        7739 :     SetMetadataItem("SOURCE_ENCODING", m_osEncoding, "SHAPEFILE");
     136             : 
     137             :     auto fpShpXML = VSIFilesystemHandler::OpenStatic(
     138       15478 :         CPLResetExtensionSafe(m_osFullName.c_str(), "shp.xml").c_str(), "rb");
     139        7739 :     m_bHasShpXML = fpShpXML != nullptr;
     140             : 
     141       15478 :     m_poFeatureDefn = SHPReadOGRFeatureDefn(
     142       15478 :         CPLGetBasenameSafe(m_osFullName.c_str()).c_str(), m_hSHP, m_hDBF,
     143             :         fpShpXML.get(), m_osEncoding,
     144        7739 :         CPLFetchBool(m_poDS->GetOpenOptions(), "ADJUST_TYPE", false));
     145             : 
     146             :     // To make sure that
     147             :     //  GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef() == GetSpatialRef()
     148        7739 :     OGRwkbGeometryType eGeomType = m_poFeatureDefn->GetGeomType();
     149        7739 :     if (eGeomType != wkbNone)
     150             :     {
     151        6951 :         OGRwkbGeometryType eType = wkbUnknown;
     152             : 
     153        6951 :         if (m_eRequestedGeomType == wkbNone)
     154             :         {
     155        5330 :             eType = eGeomType;
     156             : 
     157        5330 :             const char *pszAdjustGeomType = CSLFetchNameValueDef(
     158        5330 :                 m_poDS->GetOpenOptions(), "ADJUST_GEOM_TYPE", "FIRST_SHAPE");
     159        5330 :             const bool bFirstShape = EQUAL(pszAdjustGeomType, "FIRST_SHAPE");
     160        5330 :             const bool bAllShapes = EQUAL(pszAdjustGeomType, "ALL_SHAPES");
     161        5330 :             if ((m_hSHP != nullptr) && (m_hSHP->nRecords > 0) &&
     162       10660 :                 wkbHasM(eType) && (bFirstShape || bAllShapes))
     163             :             {
     164         511 :                 bool bMIsUsed = false;
     165         512 :                 for (int iShape = 0; iShape < m_hSHP->nRecords; iShape++)
     166             :                 {
     167         512 :                     SHPObject *psShape = SHPReadObject(m_hSHP, iShape);
     168         512 :                     if (psShape)
     169             :                     {
     170         512 :                         if (psShape->bMeasureIsUsed && psShape->nVertices > 0 &&
     171          51 :                             psShape->padfM != nullptr)
     172             :                         {
     173          56 :                             for (int i = 0; i < psShape->nVertices; i++)
     174             :                             {
     175             :                                 // Per the spec, if the M value is smaller than
     176             :                                 // -1e38, it is a nodata value.
     177          51 :                                 if (psShape->padfM[i] > -1e38)
     178             :                                 {
     179          46 :                                     bMIsUsed = true;
     180          46 :                                     break;
     181             :                                 }
     182             :                             }
     183             :                         }
     184             : 
     185         512 :                         SHPDestroyObject(psShape);
     186             :                     }
     187         512 :                     if (bFirstShape || bMIsUsed)
     188             :                         break;
     189             :                 }
     190         511 :                 if (!bMIsUsed)
     191         465 :                     eType = OGR_GT_SetModifier(eType, wkbHasZ(eType), FALSE);
     192             :             }
     193             :         }
     194             :         else
     195             :         {
     196        1621 :             eType = m_eRequestedGeomType;
     197             :         }
     198             : 
     199        6951 :         OGRSpatialReference *poSRSClone = poSRSIn ? poSRSIn->Clone() : nullptr;
     200        6951 :         if (poSRSClone)
     201             :         {
     202         220 :             poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     203             :         }
     204             :         auto poGeomFieldDefn = std::make_unique<OGRShapeGeomFieldDefn>(
     205        6951 :             m_osFullName.c_str(), eType, bSRSSetIn, poSRSClone);
     206        6951 :         if (!osPrjFilename.empty())
     207         220 :             poGeomFieldDefn->SetPrjFilename(osPrjFilename);
     208        6951 :         if (poSRSClone)
     209         220 :             poSRSClone->Release();
     210        6951 :         m_poFeatureDefn->SetGeomType(wkbNone);
     211        6951 :         m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
     212             :     }
     213             : 
     214        7739 :     SetDescription(m_poFeatureDefn->GetName());
     215        7739 :     m_bRewindOnWrite = CPLTestBool(CPLGetConfigOption(
     216             :         "SHAPE_REWIND_ON_WRITE",
     217        7739 :         m_hSHP != nullptr && m_hSHP->nShapeType != SHPT_MULTIPATCH ? "NO"
     218             :                                                                    : "YES"));
     219             : 
     220        7739 :     m_poFeatureDefn->Seal(/* bSealFields = */ true);
     221        7739 : }
     222             : 
     223             : /************************************************************************/
     224             : /*                           ~OGRShapeLayer()                           */
     225             : /************************************************************************/
     226             : 
     227       15464 : OGRShapeLayer::~OGRShapeLayer()
     228             : 
     229             : {
     230        7732 :     if (m_eNeedRepack == YES && m_bAutoRepack)
     231           2 :         Repack();
     232             : 
     233        7732 :     if (m_bResizeAtClose && m_hDBF != nullptr)
     234             :     {
     235           1 :         ResizeDBF();
     236             :     }
     237        7732 :     if (m_bCreateSpatialIndexAtClose && m_hSHP != nullptr)
     238             :     {
     239           1 :         CreateSpatialIndex(0);
     240             :     }
     241             : 
     242        7732 :     if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
     243             :     {
     244        4490 :         CPLDebug("Shape", "%d features read on layer '%s'.",
     245        2245 :                  static_cast<int>(m_nFeaturesRead), m_poFeatureDefn->GetName());
     246             :     }
     247             : 
     248        7732 :     ClearMatchingFIDs();
     249        7732 :     ClearSpatialFIDs();
     250             : 
     251        7732 :     if (m_poFeatureDefn != nullptr)
     252        7732 :         m_poFeatureDefn->Release();
     253             : 
     254        7732 :     if (m_hDBF != nullptr)
     255        4873 :         DBFClose(m_hDBF);
     256             : 
     257        7732 :     if (m_hSHP != nullptr)
     258        4143 :         SHPClose(m_hSHP);
     259             : 
     260        7732 :     if (m_hQIX != nullptr)
     261          36 :         SHPCloseDiskTree(m_hQIX);
     262             : 
     263        7732 :     if (m_hSBN != nullptr)
     264           3 :         SBNCloseDiskTree(m_hSBN);
     265       15464 : }
     266             : 
     267             : /************************************************************************/
     268             : /*                       SetModificationDate()                          */
     269             : /************************************************************************/
     270             : 
     271        7739 : void OGRShapeLayer::SetModificationDate(const char *pszStr)
     272             : {
     273        7739 :     if (m_hDBF && pszStr)
     274             :     {
     275          50 :         int year = 0;
     276          50 :         int month = 0;
     277          50 :         int day = 0;
     278         100 :         if ((sscanf(pszStr, "%04d-%02d-%02d", &year, &month, &day) == 3 ||
     279         100 :              sscanf(pszStr, "%04d/%02d/%02d", &year, &month, &day) == 3) &&
     280          50 :             (year >= 1900 && year <= 1900 + 255 && month >= 1 && month <= 12 &&
     281          50 :              day >= 1 && day <= 31))
     282             :         {
     283          50 :             DBFSetLastModifiedDate(m_hDBF, year - 1900, month, day);
     284             :         }
     285             :     }
     286        7739 : }
     287             : 
     288             : /************************************************************************/
     289             : /*                       SetWriteDBFEOFChar()                           */
     290             : /************************************************************************/
     291             : 
     292        7739 : void OGRShapeLayer::SetWriteDBFEOFChar(bool b)
     293             : {
     294        7739 :     if (m_hDBF)
     295             :     {
     296        7679 :         DBFSetWriteEndOfFileChar(m_hDBF, b);
     297             :     }
     298        7739 : }
     299             : 
     300             : /************************************************************************/
     301             : /*                          ConvertCodePage()                           */
     302             : /************************************************************************/
     303             : 
     304        6310 : static CPLString GetEncodingFromLDIDNumber(int nLDID)
     305             : {
     306        6310 :     int nCP = -1;  // Windows code page.
     307             : 
     308             :     // http://www.autopark.ru/ASBProgrammerGuide/DBFSTRUC.HTM
     309        6310 :     switch (nLDID)
     310             :     {
     311           0 :         case 1:
     312           0 :             nCP = 437;
     313           0 :             break;
     314           0 :         case 2:
     315           0 :             nCP = 850;
     316           0 :             break;
     317           1 :         case 3:
     318           1 :             nCP = 1252;
     319           1 :             break;
     320           0 :         case 4:
     321           0 :             nCP = 10000;
     322           0 :             break;
     323           0 :         case 8:
     324           0 :             nCP = 865;
     325           0 :             break;
     326           0 :         case 10:
     327           0 :             nCP = 850;
     328           0 :             break;
     329           0 :         case 11:
     330           0 :             nCP = 437;
     331           0 :             break;
     332           0 :         case 13:
     333           0 :             nCP = 437;
     334           0 :             break;
     335           0 :         case 14:
     336           0 :             nCP = 850;
     337           0 :             break;
     338           0 :         case 15:
     339           0 :             nCP = 437;
     340           0 :             break;
     341           0 :         case 16:
     342           0 :             nCP = 850;
     343           0 :             break;
     344           0 :         case 17:
     345           0 :             nCP = 437;
     346           0 :             break;
     347           0 :         case 18:
     348           0 :             nCP = 850;
     349           0 :             break;
     350           0 :         case 19:
     351           0 :             nCP = 932;
     352           0 :             break;
     353           0 :         case 20:
     354           0 :             nCP = 850;
     355           0 :             break;
     356           0 :         case 21:
     357           0 :             nCP = 437;
     358           0 :             break;
     359           0 :         case 22:
     360           0 :             nCP = 850;
     361           0 :             break;
     362           0 :         case 23:
     363           0 :             nCP = 865;
     364           0 :             break;
     365           0 :         case 24:
     366           0 :             nCP = 437;
     367           0 :             break;
     368           0 :         case 25:
     369           0 :             nCP = 437;
     370           0 :             break;
     371           0 :         case 26:
     372           0 :             nCP = 850;
     373           0 :             break;
     374           0 :         case 27:
     375           0 :             nCP = 437;
     376           0 :             break;
     377           0 :         case 28:
     378           0 :             nCP = 863;
     379           0 :             break;
     380           0 :         case 29:
     381           0 :             nCP = 850;
     382           0 :             break;
     383           0 :         case 31:
     384           0 :             nCP = 852;
     385           0 :             break;
     386           0 :         case 34:
     387           0 :             nCP = 852;
     388           0 :             break;
     389           0 :         case 35:
     390           0 :             nCP = 852;
     391           0 :             break;
     392           0 :         case 36:
     393           0 :             nCP = 860;
     394           0 :             break;
     395           0 :         case 37:
     396           0 :             nCP = 850;
     397           0 :             break;
     398           0 :         case 38:
     399           0 :             nCP = 866;
     400           0 :             break;
     401           0 :         case 55:
     402           0 :             nCP = 850;
     403           0 :             break;
     404           0 :         case 64:
     405           0 :             nCP = 852;
     406           0 :             break;
     407           1 :         case 77:
     408           1 :             nCP = 936;
     409           1 :             break;
     410           0 :         case 78:
     411           0 :             nCP = 949;
     412           0 :             break;
     413           0 :         case 79:
     414           0 :             nCP = 950;
     415           0 :             break;
     416           0 :         case 80:
     417           0 :             nCP = 874;
     418           0 :             break;
     419        6183 :         case 87:
     420        6183 :             return CPL_ENC_ISO8859_1;
     421         125 :         case 88:
     422         125 :             nCP = 1252;
     423         125 :             break;
     424           0 :         case 89:
     425           0 :             nCP = 1252;
     426           0 :             break;
     427           0 :         case 100:
     428           0 :             nCP = 852;
     429           0 :             break;
     430           0 :         case 101:
     431           0 :             nCP = 866;
     432           0 :             break;
     433           0 :         case 102:
     434           0 :             nCP = 865;
     435           0 :             break;
     436           0 :         case 103:
     437           0 :             nCP = 861;
     438           0 :             break;
     439           0 :         case 104:
     440           0 :             nCP = 895;
     441           0 :             break;
     442           0 :         case 105:
     443           0 :             nCP = 620;
     444           0 :             break;
     445           0 :         case 106:
     446           0 :             nCP = 737;
     447           0 :             break;
     448           0 :         case 107:
     449           0 :             nCP = 857;
     450           0 :             break;
     451           0 :         case 108:
     452           0 :             nCP = 863;
     453           0 :             break;
     454           0 :         case 120:
     455           0 :             nCP = 950;
     456           0 :             break;
     457           0 :         case 121:
     458           0 :             nCP = 949;
     459           0 :             break;
     460           0 :         case 122:
     461           0 :             nCP = 936;
     462           0 :             break;
     463           0 :         case 123:
     464           0 :             nCP = 932;
     465           0 :             break;
     466           0 :         case 124:
     467           0 :             nCP = 874;
     468           0 :             break;
     469           0 :         case 134:
     470           0 :             nCP = 737;
     471           0 :             break;
     472           0 :         case 135:
     473           0 :             nCP = 852;
     474           0 :             break;
     475           0 :         case 136:
     476           0 :             nCP = 857;
     477           0 :             break;
     478           0 :         case 150:
     479           0 :             nCP = 10007;
     480           0 :             break;
     481           0 :         case 151:
     482           0 :             nCP = 10029;
     483           0 :             break;
     484           0 :         case 200:
     485           0 :             nCP = 1250;
     486           0 :             break;
     487           0 :         case 201:
     488           0 :             nCP = 1251;
     489           0 :             break;
     490           0 :         case 202:
     491           0 :             nCP = 1254;
     492           0 :             break;
     493           0 :         case 203:
     494           0 :             nCP = 1253;
     495           0 :             break;
     496           0 :         case 204:
     497           0 :             nCP = 1257;
     498           0 :             break;
     499           0 :         default:
     500           0 :             break;
     501             :     }
     502             : 
     503         127 :     if (nCP < 0)
     504           0 :         return CPLString();
     505         254 :     return CPLString().Printf("CP%d", nCP);
     506             : }
     507             : 
     508          49 : static CPLString GetEncodingFromCPG(const char *pszCPG)
     509             : {
     510             :     // see https://support.esri.com/en/technical-article/000013192
     511          49 :     CPLString m_osEncodingFromCPG;
     512          49 :     const int nCPG = atoi(pszCPG);
     513          49 :     if ((nCPG >= 437 && nCPG <= 950) || (nCPG >= 1250 && nCPG <= 1258))
     514             :     {
     515           0 :         m_osEncodingFromCPG.Printf("CP%d", nCPG);
     516             :     }
     517          49 :     else if (STARTS_WITH_CI(pszCPG, "8859"))
     518             :     {
     519           0 :         if (pszCPG[4] == '-')
     520           0 :             m_osEncodingFromCPG.Printf("ISO-8859-%s", pszCPG + 5);
     521             :         else
     522           0 :             m_osEncodingFromCPG.Printf("ISO-8859-%s", pszCPG + 4);
     523             :     }
     524          49 :     else if (STARTS_WITH_CI(pszCPG, "UTF-8") || STARTS_WITH_CI(pszCPG, "UTF8"))
     525          48 :         m_osEncodingFromCPG = CPL_ENC_UTF8;
     526           1 :     else if (STARTS_WITH_CI(pszCPG, "ANSI 1251"))
     527           0 :         m_osEncodingFromCPG = "CP1251";
     528             :     else
     529             :     {
     530             :         // Try just using the CPG value directly.  Works for stuff like Big5.
     531           1 :         m_osEncodingFromCPG = pszCPG;
     532             :     }
     533          49 :     return m_osEncodingFromCPG;
     534             : }
     535             : 
     536        6356 : CPLString OGRShapeLayer::ConvertCodePage(const char *pszCodePage)
     537             : 
     538             : {
     539        6356 :     CPLString l_m_osEncoding;
     540             : 
     541        6356 :     if (pszCodePage == nullptr)
     542           0 :         return l_m_osEncoding;
     543             : 
     544       12712 :     std::string m_osEncodingFromLDID;
     545        6356 :     if (m_hDBF->iLanguageDriver != 0)
     546             :     {
     547        6310 :         SetMetadataItem("LDID_VALUE", CPLSPrintf("%d", m_hDBF->iLanguageDriver),
     548        6310 :                         "SHAPEFILE");
     549             : 
     550             :         m_osEncodingFromLDID =
     551        6310 :             GetEncodingFromLDIDNumber(m_hDBF->iLanguageDriver);
     552             :     }
     553        6356 :     if (!m_osEncodingFromLDID.empty())
     554             :     {
     555        6310 :         SetMetadataItem("ENCODING_FROM_LDID", m_osEncodingFromLDID.c_str(),
     556        6310 :                         "SHAPEFILE");
     557             :     }
     558             : 
     559       12712 :     std::string m_osEncodingFromCPG;
     560        6356 :     if (!STARTS_WITH_CI(pszCodePage, "LDID/"))
     561             :     {
     562          49 :         SetMetadataItem("CPG_VALUE", pszCodePage, "SHAPEFILE");
     563             : 
     564          49 :         m_osEncodingFromCPG = GetEncodingFromCPG(pszCodePage);
     565             : 
     566          49 :         if (!m_osEncodingFromCPG.empty())
     567          49 :             SetMetadataItem("ENCODING_FROM_CPG", m_osEncodingFromCPG.c_str(),
     568          49 :                             "SHAPEFILE");
     569             : 
     570          49 :         l_m_osEncoding = std::move(m_osEncodingFromCPG);
     571             :     }
     572        6307 :     else if (!m_osEncodingFromLDID.empty())
     573             :     {
     574        6307 :         l_m_osEncoding = std::move(m_osEncodingFromLDID);
     575             :     }
     576             : 
     577        6356 :     return l_m_osEncoding;
     578             : }
     579             : 
     580             : /************************************************************************/
     581             : /*                            CheckForQIX()                             */
     582             : /************************************************************************/
     583             : 
     584       67194 : bool OGRShapeLayer::CheckForQIX()
     585             : 
     586             : {
     587       67194 :     if (m_bCheckedForQIX)
     588       65396 :         return m_hQIX != nullptr;
     589             : 
     590             :     const std::string osQIXFilename =
     591        1798 :         CPLResetExtensionSafe(m_osFullName.c_str(), "qix");
     592             : 
     593        1798 :     m_hQIX = SHPOpenDiskTree(osQIXFilename.c_str(), nullptr);
     594             : 
     595        1798 :     m_bCheckedForQIX = true;
     596             : 
     597        1798 :     return m_hQIX != nullptr;
     598             : }
     599             : 
     600             : /************************************************************************/
     601             : /*                            CheckForSBN()                             */
     602             : /************************************************************************/
     603             : 
     604       67107 : bool OGRShapeLayer::CheckForSBN()
     605             : 
     606             : {
     607       67107 :     if (m_bCheckedForSBN)
     608       65355 :         return m_hSBN != nullptr;
     609             : 
     610             :     const std::string osSBNFilename =
     611        1752 :         CPLResetExtensionSafe(m_osFullName.c_str(), "sbn");
     612             : 
     613        1752 :     m_hSBN = SBNOpenDiskTree(osSBNFilename.c_str(), nullptr);
     614             : 
     615        1752 :     m_bCheckedForSBN = true;
     616             : 
     617        1752 :     return m_hSBN != nullptr;
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                            ScanIndices()                             */
     622             : /*                                                                      */
     623             : /*      Utilize optional spatial and attribute indices if they are      */
     624             : /*      available.                                                      */
     625             : /************************************************************************/
     626             : 
     627       13453 : bool OGRShapeLayer::ScanIndices()
     628             : 
     629             : {
     630       13453 :     m_iMatchingFID = 0;
     631             : 
     632             :     /* -------------------------------------------------------------------- */
     633             :     /*      Utilize attribute index if appropriate.                         */
     634             :     /* -------------------------------------------------------------------- */
     635       13453 :     if (m_poAttrQuery != nullptr)
     636             :     {
     637         585 :         CPLAssert(m_panMatchingFIDs == nullptr);
     638             : 
     639         585 :         InitializeIndexSupport(m_osFullName.c_str());
     640             : 
     641         585 :         m_panMatchingFIDs =
     642         585 :             m_poAttrQuery->EvaluateAgainstIndices(this, nullptr);
     643             :     }
     644             : 
     645             :     /* -------------------------------------------------------------------- */
     646             :     /*      Check for spatial index if we have a spatial query.             */
     647             :     /* -------------------------------------------------------------------- */
     648             : 
     649       13453 :     if (m_poFilterGeom == nullptr || m_hSHP == nullptr)
     650         551 :         return true;
     651             : 
     652       12902 :     OGREnvelope oSpatialFilterEnvelope;
     653       12902 :     bool bTryQIXorSBN = true;
     654             : 
     655       12902 :     m_poFilterGeom->getEnvelope(&oSpatialFilterEnvelope);
     656             : 
     657       12902 :     OGREnvelope oLayerExtent;
     658       12902 :     if (GetExtent(&oLayerExtent, TRUE) == OGRERR_NONE)
     659             :     {
     660       12902 :         if (oSpatialFilterEnvelope.Contains(oLayerExtent))
     661             :         {
     662             :             // The spatial filter is larger than the layer extent. No use of
     663             :             // .qix file for now.
     664          90 :             return true;
     665             :         }
     666       12812 :         else if (!oSpatialFilterEnvelope.Intersects(oLayerExtent))
     667             :         {
     668             :             // No intersection : no need to check for .qix or .sbn.
     669          40 :             bTryQIXorSBN = false;
     670             : 
     671             :             // Set an empty result for spatial FIDs.
     672          40 :             free(m_panSpatialFIDs);
     673          40 :             m_panSpatialFIDs = static_cast<int *>(calloc(1, sizeof(int)));
     674          40 :             m_nSpatialFIDCount = 0;
     675             : 
     676          40 :             delete m_poFilterGeomLastValid;
     677          40 :             m_poFilterGeomLastValid = m_poFilterGeom->clone();
     678             :         }
     679             :     }
     680             : 
     681       12812 :     if (bTryQIXorSBN)
     682             :     {
     683       12772 :         if (!m_bCheckedForQIX)
     684          74 :             CPL_IGNORE_RET_VAL(CheckForQIX());
     685       12772 :         if (m_hQIX == nullptr && !m_bCheckedForSBN)
     686          58 :             CPL_IGNORE_RET_VAL(CheckForSBN());
     687             :     }
     688             : 
     689             :     /* -------------------------------------------------------------------- */
     690             :     /*      Compute spatial index if appropriate.                           */
     691             :     /* -------------------------------------------------------------------- */
     692       12812 :     if (bTryQIXorSBN && (m_hQIX != nullptr || m_hSBN != nullptr) &&
     693       12335 :         m_panSpatialFIDs == nullptr)
     694             :     {
     695       12330 :         double adfBoundsMin[4] = {oSpatialFilterEnvelope.MinX,
     696       12330 :                                   oSpatialFilterEnvelope.MinY, 0.0, 0.0};
     697       12330 :         double adfBoundsMax[4] = {oSpatialFilterEnvelope.MaxX,
     698       12330 :                                   oSpatialFilterEnvelope.MaxY, 0.0, 0.0};
     699             : 
     700       12330 :         if (m_hQIX != nullptr)
     701       12324 :             m_panSpatialFIDs = SHPSearchDiskTreeEx(
     702             :                 m_hQIX, adfBoundsMin, adfBoundsMax, &m_nSpatialFIDCount);
     703             :         else
     704           6 :             m_panSpatialFIDs = SBNSearchDiskTree(
     705             :                 m_hSBN, adfBoundsMin, adfBoundsMax, &m_nSpatialFIDCount);
     706             : 
     707       12330 :         CPLDebug("SHAPE", "Used spatial index, got %d matches.",
     708             :                  m_nSpatialFIDCount);
     709             : 
     710       12330 :         delete m_poFilterGeomLastValid;
     711       12330 :         m_poFilterGeomLastValid = m_poFilterGeom->clone();
     712             :     }
     713             : 
     714             :     /* -------------------------------------------------------------------- */
     715             :     /*      Use spatial index if appropriate.                               */
     716             :     /* -------------------------------------------------------------------- */
     717       12812 :     if (m_panSpatialFIDs != nullptr)
     718             :     {
     719             :         // Use resulting list as matching FID list (but reallocate and
     720             :         // terminate with OGRNullFID).
     721       12375 :         if (m_panMatchingFIDs == nullptr)
     722             :         {
     723       12373 :             m_panMatchingFIDs = static_cast<GIntBig *>(
     724       12373 :                 CPLMalloc(sizeof(GIntBig) * (m_nSpatialFIDCount + 1)));
     725      217397 :             for (int i = 0; i < m_nSpatialFIDCount; i++)
     726      205024 :                 m_panMatchingFIDs[i] =
     727      205024 :                     static_cast<GIntBig>(m_panSpatialFIDs[i]);
     728       12373 :             m_panMatchingFIDs[m_nSpatialFIDCount] = OGRNullFID;
     729             :         }
     730             :         // Cull attribute index matches based on those in the spatial index
     731             :         // result set.  We assume that the attribute results are in sorted
     732             :         // order.
     733             :         else
     734             :         {
     735           2 :             int iWrite = 0;
     736           2 :             int iSpatial = 0;
     737             : 
     738           4 :             for (int iRead = 0; m_panMatchingFIDs[iRead] != OGRNullFID; iRead++)
     739             :             {
     740           7 :                 while (iSpatial < m_nSpatialFIDCount &&
     741           7 :                        m_panSpatialFIDs[iSpatial] < m_panMatchingFIDs[iRead])
     742           5 :                     iSpatial++;
     743             : 
     744           2 :                 if (iSpatial == m_nSpatialFIDCount)
     745           0 :                     continue;
     746             : 
     747           2 :                 if (m_panSpatialFIDs[iSpatial] == m_panMatchingFIDs[iRead])
     748           2 :                     m_panMatchingFIDs[iWrite++] = m_panMatchingFIDs[iRead];
     749             :             }
     750           2 :             m_panMatchingFIDs[iWrite] = OGRNullFID;
     751             :         }
     752             : 
     753       12375 :         if (m_nSpatialFIDCount > 100000)
     754             :         {
     755           0 :             ClearSpatialFIDs();
     756             :         }
     757             :     }
     758             : 
     759       12812 :     return true;
     760             : }
     761             : 
     762             : /************************************************************************/
     763             : /*                            ResetReading()                            */
     764             : /************************************************************************/
     765             : 
     766       31069 : void OGRShapeLayer::ResetReading()
     767             : 
     768             : {
     769       31069 :     if (!TouchLayer())
     770           0 :         return;
     771             : 
     772       31069 :     m_iMatchingFID = 0;
     773             : 
     774       31069 :     m_iNextShapeId = 0;
     775             : 
     776       31069 :     if (m_bHeaderDirty && m_bUpdateAccess)
     777         141 :         SyncToDisk();
     778             : 
     779       31069 :     if (m_hDBF)
     780       31030 :         VSIFClearErrL(VSI_SHP_GetVSIL(m_hDBF->fp));
     781             : }
     782             : 
     783             : /************************************************************************/
     784             : /*                        ClearMatchingFIDs()                           */
     785             : /************************************************************************/
     786             : 
     787       25533 : void OGRShapeLayer::ClearMatchingFIDs()
     788             : {
     789             :     /* -------------------------------------------------------------------- */
     790             :     /*      Clear previous index search result, if any.                     */
     791             :     /* -------------------------------------------------------------------- */
     792       25533 :     CPLFree(m_panMatchingFIDs);
     793       25533 :     m_panMatchingFIDs = nullptr;
     794       25533 : }
     795             : 
     796             : /************************************************************************/
     797             : /*                        ClearSpatialFIDs()                           */
     798             : /************************************************************************/
     799             : 
     800       20056 : void OGRShapeLayer::ClearSpatialFIDs()
     801             : {
     802       20056 :     if (m_panSpatialFIDs != nullptr)
     803             :     {
     804       12360 :         CPLDebug("SHAPE", "Clear m_panSpatialFIDs");
     805       12360 :         free(m_panSpatialFIDs);
     806             :     }
     807       20056 :     m_panSpatialFIDs = nullptr;
     808       20056 :     m_nSpatialFIDCount = 0;
     809             : 
     810       20056 :     delete m_poFilterGeomLastValid;
     811       20056 :     m_poFilterGeomLastValid = nullptr;
     812       20056 : }
     813             : 
     814             : /************************************************************************/
     815             : /*                         ISetSpatialFilter()                          */
     816             : /************************************************************************/
     817             : 
     818       15053 : OGRErr OGRShapeLayer::ISetSpatialFilter(int iGeomField,
     819             :                                         const OGRGeometry *poGeomIn)
     820             : {
     821       15053 :     ClearMatchingFIDs();
     822             : 
     823       15053 :     if (poGeomIn == nullptr)
     824             :     {
     825             :         // Do nothing.
     826             :     }
     827       25185 :     else if (m_poFilterGeomLastValid != nullptr &&
     828       12331 :              m_poFilterGeomLastValid->Equals(poGeomIn))
     829             :     {
     830             :         // Do nothing.
     831             :     }
     832       12839 :     else if (m_panSpatialFIDs != nullptr)
     833             :     {
     834             :         // We clear the spatialFIDs only if we have a new non-NULL spatial
     835             :         // filter, otherwise we keep the previous result cached. This can be
     836             :         // useful when several SQL layers rely on the same table layer, and use
     837             :         // the same spatial filters. But as there is in the destructor of
     838             :         // OGRGenSQLResultsLayer a clearing of the spatial filter of the table
     839             :         // layer, we need this trick.
     840       12316 :         ClearSpatialFIDs();
     841             :     }
     842             : 
     843       15053 :     return OGRLayer::ISetSpatialFilter(iGeomField, poGeomIn);
     844             : }
     845             : 
     846             : /************************************************************************/
     847             : /*                         SetAttributeFilter()                         */
     848             : /************************************************************************/
     849             : 
     850        2748 : OGRErr OGRShapeLayer::SetAttributeFilter(const char *pszAttributeFilter)
     851             : {
     852        2748 :     ClearMatchingFIDs();
     853             : 
     854        2748 :     return OGRLayer::SetAttributeFilter(pszAttributeFilter);
     855             : }
     856             : 
     857             : /************************************************************************/
     858             : /*                           SetNextByIndex()                           */
     859             : /*                                                                      */
     860             : /*      If we already have an FID list, we can easily reposition        */
     861             : /*      ourselves in it.                                                */
     862             : /************************************************************************/
     863             : 
     864          47 : OGRErr OGRShapeLayer::SetNextByIndex(GIntBig nIndex)
     865             : 
     866             : {
     867          47 :     if (!TouchLayer())
     868           0 :         return OGRERR_FAILURE;
     869             : 
     870          47 :     if (nIndex < 0 || nIndex >= m_nTotalShapeCount)
     871             :     {
     872          13 :         m_iNextShapeId = m_nTotalShapeCount;
     873          13 :         return OGRERR_NON_EXISTING_FEATURE;
     874             :     }
     875             : 
     876             :     // Eventually we should try to use m_panMatchingFIDs list
     877             :     // if available and appropriate.
     878          34 :     if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
     879           1 :         return OGRLayer::SetNextByIndex(nIndex);
     880             : 
     881          33 :     m_iNextShapeId = static_cast<int>(nIndex);
     882             : 
     883          33 :     return OGRERR_NONE;
     884             : }
     885             : 
     886             : /************************************************************************/
     887             : /*                             FetchShape()                             */
     888             : /*                                                                      */
     889             : /*      Take a shape id, a geometry, and a feature, and set the feature */
     890             : /*      if the shapeid bbox intersects the geometry.                    */
     891             : /************************************************************************/
     892             : 
     893      186626 : OGRFeature *OGRShapeLayer::FetchShape(int iShapeId)
     894             : 
     895             : {
     896      186626 :     OGRFeature *poFeature = nullptr;
     897             : 
     898      186626 :     if (m_poFilterGeom != nullptr && m_hSHP != nullptr)
     899             :     {
     900      121807 :         SHPObject *psShape = SHPReadObject(m_hSHP, iShapeId);
     901             : 
     902             :         // do not trust degenerate bounds on non-point geometries
     903             :         // or bounds on null shapes.
     904      121807 :         if (psShape == nullptr ||
     905      121802 :             (psShape->nSHPType != SHPT_POINT &&
     906      119219 :              psShape->nSHPType != SHPT_POINTZ &&
     907      104578 :              psShape->nSHPType != SHPT_POINTM &&
     908      104578 :              (psShape->dfXMin == psShape->dfXMax ||
     909      104572 :               psShape->dfYMin == psShape->dfYMax)) ||
     910      121796 :             psShape->nSHPType == SHPT_NULL)
     911             :         {
     912          11 :             poFeature = SHPReadOGRFeature(m_hSHP, m_hDBF, m_poFeatureDefn,
     913             :                                           iShapeId, psShape, m_osEncoding,
     914          11 :                                           m_bHasWarnedWrongWindingOrder);
     915             :         }
     916      121796 :         else if (m_sFilterEnvelope.MaxX < psShape->dfXMin ||
     917       79231 :                  m_sFilterEnvelope.MaxY < psShape->dfYMin ||
     918       56429 :                  psShape->dfXMax < m_sFilterEnvelope.MinX ||
     919       36850 :                  psShape->dfYMax < m_sFilterEnvelope.MinY)
     920             :         {
     921       90408 :             SHPDestroyObject(psShape);
     922       90408 :             poFeature = nullptr;
     923             :         }
     924             :         else
     925             :         {
     926       31388 :             poFeature = SHPReadOGRFeature(m_hSHP, m_hDBF, m_poFeatureDefn,
     927             :                                           iShapeId, psShape, m_osEncoding,
     928       31388 :                                           m_bHasWarnedWrongWindingOrder);
     929      121807 :         }
     930             :     }
     931             :     else
     932             :     {
     933       64819 :         poFeature = SHPReadOGRFeature(m_hSHP, m_hDBF, m_poFeatureDefn, iShapeId,
     934             :                                       nullptr, m_osEncoding,
     935       64819 :                                       m_bHasWarnedWrongWindingOrder);
     936             :     }
     937             : 
     938      186626 :     return poFeature;
     939             : }
     940             : 
     941             : /************************************************************************/
     942             : /*                           GetNextFeature()                           */
     943             : /************************************************************************/
     944             : 
     945       94385 : OGRFeature *OGRShapeLayer::GetNextFeature()
     946             : 
     947             : {
     948       94385 :     if (!TouchLayer())
     949           0 :         return nullptr;
     950             : 
     951             :     /* -------------------------------------------------------------------- */
     952             :     /*      Collect a matching list if we have attribute or spatial         */
     953             :     /*      indices.  Only do this on the first request for a given pass    */
     954             :     /*      of course.                                                      */
     955             :     /* -------------------------------------------------------------------- */
     956       94385 :     if ((m_poAttrQuery != nullptr || m_poFilterGeom != nullptr) &&
     957       32654 :         m_iNextShapeId == 0 && m_panMatchingFIDs == nullptr)
     958             :     {
     959       13416 :         ScanIndices();
     960             :     }
     961             : 
     962             :     /* -------------------------------------------------------------------- */
     963             :     /*      Loop till we find a feature matching our criteria.              */
     964             :     /* -------------------------------------------------------------------- */
     965       94385 :     OGRFeature *poFeature = nullptr;
     966             : 
     967             :     while (true)
     968             :     {
     969      188308 :         if (m_panMatchingFIDs != nullptr)
     970             :         {
     971      101464 :             if (m_panMatchingFIDs[m_iMatchingFID] == OGRNullFID)
     972             :             {
     973          52 :                 return nullptr;
     974             :             }
     975             : 
     976             :             // Check the shape object's geometry, and if it matches
     977             :             // any spatial filter, return it.
     978             :             poFeature =
     979      101412 :                 FetchShape(static_cast<int>(m_panMatchingFIDs[m_iMatchingFID]));
     980             : 
     981      101412 :             m_iMatchingFID++;
     982             :         }
     983             :         else
     984             :         {
     985       86844 :             if (m_iNextShapeId >= m_nTotalShapeCount)
     986             :             {
     987        1628 :                 return nullptr;
     988             :             }
     989             : 
     990       85216 :             if (m_hDBF)
     991             :             {
     992       85174 :                 if (DBFIsRecordDeleted(m_hDBF, m_iNextShapeId))
     993           2 :                     poFeature = nullptr;
     994      170344 :                 else if (VSIFEofL(VSI_SHP_GetVSIL(m_hDBF->fp)) ||
     995       85172 :                          VSIFErrorL(VSI_SHP_GetVSIL(m_hDBF->fp)))
     996           0 :                     return nullptr;  //* I/O error.
     997             :                 else
     998       85172 :                     poFeature = FetchShape(m_iNextShapeId);
     999             :             }
    1000             :             else
    1001          42 :                 poFeature = FetchShape(m_iNextShapeId);
    1002             : 
    1003       85216 :             m_iNextShapeId++;
    1004             :         }
    1005             : 
    1006      186628 :         if (poFeature != nullptr)
    1007             :         {
    1008       96218 :             OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1009       96218 :             if (poGeom != nullptr)
    1010             :             {
    1011       90908 :                 poGeom->assignSpatialReference(GetSpatialRef());
    1012             :             }
    1013             : 
    1014       96218 :             m_nFeaturesRead++;
    1015             : 
    1016      192040 :             if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) &&
    1017       95822 :                 (m_poAttrQuery == nullptr ||
    1018       18815 :                  m_poAttrQuery->Evaluate(poFeature)))
    1019             :             {
    1020       92705 :                 return poFeature;
    1021             :             }
    1022             : 
    1023        3513 :             delete poFeature;
    1024             :         }
    1025       93923 :     }
    1026             : }
    1027             : 
    1028             : /************************************************************************/
    1029             : /*                             GetFeature()                             */
    1030             : /************************************************************************/
    1031             : 
    1032         258 : OGRFeature *OGRShapeLayer::GetFeature(GIntBig nFeatureId)
    1033             : 
    1034             : {
    1035         258 :     if (!TouchLayer() || nFeatureId > INT_MAX)
    1036           8 :         return nullptr;
    1037             : 
    1038         250 :     OGRFeature *poFeature = SHPReadOGRFeature(
    1039             :         m_hSHP, m_hDBF, m_poFeatureDefn, static_cast<int>(nFeatureId), nullptr,
    1040         250 :         m_osEncoding, m_bHasWarnedWrongWindingOrder);
    1041             : 
    1042         250 :     if (poFeature == nullptr)
    1043             :     {
    1044             :         // Reading shape feature failed.
    1045          23 :         return nullptr;
    1046             :     }
    1047             : 
    1048         227 :     if (poFeature->GetGeometryRef() != nullptr)
    1049             :     {
    1050         138 :         poFeature->GetGeometryRef()->assignSpatialReference(GetSpatialRef());
    1051             :     }
    1052             : 
    1053         227 :     m_nFeaturesRead++;
    1054             : 
    1055         227 :     return poFeature;
    1056             : }
    1057             : 
    1058             : /************************************************************************/
    1059             : /*                             StartUpdate()                            */
    1060             : /************************************************************************/
    1061             : 
    1062       72200 : bool OGRShapeLayer::StartUpdate(const char *pszOperation)
    1063             : {
    1064       72200 :     if (!m_poDS->UncompressIfNeeded())
    1065           0 :         return false;
    1066             : 
    1067       72200 :     if (!TouchLayer())
    1068           0 :         return false;
    1069             : 
    1070       72200 :     if (!m_bUpdateAccess)
    1071             :     {
    1072          10 :         CPLError(CE_Failure, CPLE_NotSupported,
    1073             :                  "%s : unsupported operation on a read-only datasource.",
    1074             :                  pszOperation);
    1075          10 :         return false;
    1076             :     }
    1077             : 
    1078       72190 :     return true;
    1079             : }
    1080             : 
    1081             : /************************************************************************/
    1082             : /*                             ISetFeature()                             */
    1083             : /************************************************************************/
    1084             : 
    1085          65 : OGRErr OGRShapeLayer::ISetFeature(OGRFeature *poFeature)
    1086             : 
    1087             : {
    1088          65 :     if (!StartUpdate("SetFeature"))
    1089           1 :         return OGRERR_FAILURE;
    1090             : 
    1091          64 :     GIntBig nFID = poFeature->GetFID();
    1092          64 :     if (nFID < 0 || (m_hSHP != nullptr && nFID >= m_hSHP->nRecords) ||
    1093          60 :         (m_hDBF != nullptr && nFID >= m_hDBF->nRecords))
    1094             :     {
    1095           4 :         return OGRERR_NON_EXISTING_FEATURE;
    1096             :     }
    1097             : 
    1098          60 :     m_bHeaderDirty = true;
    1099          60 :     if (CheckForQIX() || CheckForSBN())
    1100           2 :         DropSpatialIndex();
    1101             : 
    1102          60 :     unsigned int nOffset = 0;
    1103          60 :     unsigned int nSize = 0;
    1104          60 :     bool bIsLastRecord = false;
    1105          60 :     if (m_hSHP != nullptr)
    1106             :     {
    1107          51 :         nOffset = m_hSHP->panRecOffset[nFID];
    1108          51 :         nSize = m_hSHP->panRecSize[nFID];
    1109          51 :         bIsLastRecord = (nOffset + nSize + 8 == m_hSHP->nFileSize);
    1110             :     }
    1111             : 
    1112          60 :     OGRErr eErr = SHPWriteOGRFeature(m_hSHP, m_hDBF, m_poFeatureDefn, poFeature,
    1113             :                                      m_osEncoding, &m_bTruncationWarningEmitted,
    1114          60 :                                      m_bRewindOnWrite);
    1115             : 
    1116          60 :     if (m_hSHP != nullptr)
    1117             :     {
    1118          51 :         if (bIsLastRecord)
    1119             :         {
    1120             :             // Optimization: we don't need repacking if this is the last
    1121             :             // record of the file. Just potential truncation
    1122          19 :             CPLAssert(nOffset == m_hSHP->panRecOffset[nFID]);
    1123          19 :             CPLAssert(m_hSHP->panRecOffset[nFID] + m_hSHP->panRecSize[nFID] +
    1124             :                           8 ==
    1125             :                       m_hSHP->nFileSize);
    1126          19 :             if (m_hSHP->panRecSize[nFID] < nSize)
    1127             :             {
    1128           1 :                 VSIFTruncateL(VSI_SHP_GetVSIL(m_hSHP->fpSHP),
    1129           1 :                               m_hSHP->nFileSize);
    1130             :             }
    1131             :         }
    1132          32 :         else if (nOffset != m_hSHP->panRecOffset[nFID] ||
    1133          26 :                  nSize != m_hSHP->panRecSize[nFID])
    1134             :         {
    1135          13 :             m_bSHPNeedsRepack = true;
    1136          13 :             m_eNeedRepack = YES;
    1137             :         }
    1138             :     }
    1139             : 
    1140          60 :     return eErr;
    1141             : }
    1142             : 
    1143             : /************************************************************************/
    1144             : /*                           DeleteFeature()                            */
    1145             : /************************************************************************/
    1146             : 
    1147         223 : OGRErr OGRShapeLayer::DeleteFeature(GIntBig nFID)
    1148             : 
    1149             : {
    1150         223 :     if (!StartUpdate("DeleteFeature"))
    1151           1 :         return OGRERR_FAILURE;
    1152             : 
    1153         222 :     if (nFID < 0 || (m_hSHP != nullptr && nFID >= m_hSHP->nRecords) ||
    1154         217 :         (m_hDBF != nullptr && nFID >= m_hDBF->nRecords))
    1155             :     {
    1156           5 :         return OGRERR_NON_EXISTING_FEATURE;
    1157             :     }
    1158             : 
    1159         217 :     if (!m_hDBF)
    1160             :     {
    1161           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    1162             :                  "Attempt to delete shape in shapefile with no .dbf file.  "
    1163             :                  "Deletion is done by marking record deleted in dbf "
    1164             :                  "and is not supported without a .dbf file.");
    1165           2 :         return OGRERR_FAILURE;
    1166             :     }
    1167             : 
    1168         215 :     if (DBFIsRecordDeleted(m_hDBF, static_cast<int>(nFID)))
    1169             :     {
    1170           1 :         return OGRERR_NON_EXISTING_FEATURE;
    1171             :     }
    1172             : 
    1173         214 :     if (!DBFMarkRecordDeleted(m_hDBF, static_cast<int>(nFID), TRUE))
    1174           0 :         return OGRERR_FAILURE;
    1175             : 
    1176         214 :     m_bHeaderDirty = true;
    1177         214 :     if (CheckForQIX() || CheckForSBN())
    1178           1 :         DropSpatialIndex();
    1179         214 :     m_eNeedRepack = YES;
    1180             : 
    1181         214 :     return OGRERR_NONE;
    1182             : }
    1183             : 
    1184             : /************************************************************************/
    1185             : /*                           ICreateFeature()                            */
    1186             : /************************************************************************/
    1187             : 
    1188       66720 : OGRErr OGRShapeLayer::ICreateFeature(OGRFeature *poFeature)
    1189             : 
    1190             : {
    1191       66720 :     if (!StartUpdate("CreateFeature"))
    1192           2 :         return OGRERR_FAILURE;
    1193             : 
    1194      133435 :     if (m_hDBF != nullptr &&
    1195       66717 :         !VSI_SHP_WriteMoreDataOK(m_hDBF->fp, m_hDBF->nRecordLength))
    1196             :     {
    1197           0 :         return OGRERR_FAILURE;
    1198             :     }
    1199             : 
    1200       66718 :     m_bHeaderDirty = true;
    1201       66718 :     if (CheckForQIX() || CheckForSBN())
    1202           2 :         DropSpatialIndex();
    1203             : 
    1204       66718 :     poFeature->SetFID(OGRNullFID);
    1205             : 
    1206      135052 :     if (m_nTotalShapeCount == 0 &&
    1207        1616 :         wkbFlatten(m_eRequestedGeomType) == wkbUnknown && m_hSHP != nullptr &&
    1208       69530 :         m_hSHP->nShapeType != SHPT_MULTIPATCH &&
    1209        1196 :         poFeature->GetGeometryRef() != nullptr)
    1210             :     {
    1211         668 :         OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1212         668 :         int nShapeType = -1;
    1213             : 
    1214         668 :         switch (poGeom->getGeometryType())
    1215             :         {
    1216         545 :             case wkbPoint:
    1217         545 :                 nShapeType = SHPT_POINT;
    1218         545 :                 m_eRequestedGeomType = wkbPoint;
    1219         545 :                 break;
    1220             : 
    1221           9 :             case wkbPoint25D:
    1222           9 :                 nShapeType = SHPT_POINTZ;
    1223           9 :                 m_eRequestedGeomType = wkbPoint25D;
    1224           9 :                 break;
    1225             : 
    1226           1 :             case wkbPointM:
    1227           1 :                 nShapeType = SHPT_POINTM;
    1228           1 :                 m_eRequestedGeomType = wkbPointM;
    1229           1 :                 break;
    1230             : 
    1231           1 :             case wkbPointZM:
    1232           1 :                 nShapeType = SHPT_POINTZ;
    1233           1 :                 m_eRequestedGeomType = wkbPointZM;
    1234           1 :                 break;
    1235             : 
    1236           4 :             case wkbMultiPoint:
    1237           4 :                 nShapeType = SHPT_MULTIPOINT;
    1238           4 :                 m_eRequestedGeomType = wkbMultiPoint;
    1239           4 :                 break;
    1240             : 
    1241           2 :             case wkbMultiPoint25D:
    1242           2 :                 nShapeType = SHPT_MULTIPOINTZ;
    1243           2 :                 m_eRequestedGeomType = wkbMultiPoint25D;
    1244           2 :                 break;
    1245             : 
    1246           0 :             case wkbMultiPointM:
    1247           0 :                 nShapeType = SHPT_MULTIPOINTM;
    1248           0 :                 m_eRequestedGeomType = wkbMultiPointM;
    1249           0 :                 break;
    1250             : 
    1251           0 :             case wkbMultiPointZM:
    1252           0 :                 nShapeType = SHPT_MULTIPOINTZ;
    1253           0 :                 m_eRequestedGeomType = wkbMultiPointM;
    1254           0 :                 break;
    1255             : 
    1256          19 :             case wkbLineString:
    1257             :             case wkbMultiLineString:
    1258          19 :                 nShapeType = SHPT_ARC;
    1259          19 :                 m_eRequestedGeomType = wkbLineString;
    1260          19 :                 break;
    1261             : 
    1262           6 :             case wkbLineString25D:
    1263             :             case wkbMultiLineString25D:
    1264           6 :                 nShapeType = SHPT_ARCZ;
    1265           6 :                 m_eRequestedGeomType = wkbLineString25D;
    1266           6 :                 break;
    1267             : 
    1268           0 :             case wkbLineStringM:
    1269             :             case wkbMultiLineStringM:
    1270           0 :                 nShapeType = SHPT_ARCM;
    1271           0 :                 m_eRequestedGeomType = wkbLineStringM;
    1272           0 :                 break;
    1273             : 
    1274           0 :             case wkbLineStringZM:
    1275             :             case wkbMultiLineStringZM:
    1276           0 :                 nShapeType = SHPT_ARCZ;
    1277           0 :                 m_eRequestedGeomType = wkbLineStringZM;
    1278           0 :                 break;
    1279             : 
    1280          67 :             case wkbPolygon:
    1281             :             case wkbMultiPolygon:
    1282             :             case wkbTriangle:
    1283          67 :                 nShapeType = SHPT_POLYGON;
    1284          67 :                 m_eRequestedGeomType = wkbPolygon;
    1285          67 :                 break;
    1286             : 
    1287           7 :             case wkbPolygon25D:
    1288             :             case wkbMultiPolygon25D:
    1289             :             case wkbTriangleZ:
    1290           7 :                 nShapeType = SHPT_POLYGONZ;
    1291           7 :                 m_eRequestedGeomType = wkbPolygon25D;
    1292           7 :                 break;
    1293             : 
    1294           0 :             case wkbPolygonM:
    1295             :             case wkbMultiPolygonM:
    1296             :             case wkbTriangleM:
    1297           0 :                 nShapeType = SHPT_POLYGONM;
    1298           0 :                 m_eRequestedGeomType = wkbPolygonM;
    1299           0 :                 break;
    1300             : 
    1301           0 :             case wkbPolygonZM:
    1302             :             case wkbMultiPolygonZM:
    1303             :             case wkbTriangleZM:
    1304           0 :                 nShapeType = SHPT_POLYGONZ;
    1305           0 :                 m_eRequestedGeomType = wkbPolygonZM;
    1306           0 :                 break;
    1307             : 
    1308           7 :             default:
    1309           7 :                 nShapeType = -1;
    1310           7 :                 break;
    1311             :         }
    1312             : 
    1313        1331 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbTIN ||
    1314         663 :             wkbFlatten(poGeom->getGeometryType()) == wkbPolyhedralSurface)
    1315             :         {
    1316           6 :             nShapeType = SHPT_MULTIPATCH;
    1317           6 :             m_eRequestedGeomType = wkbUnknown;
    1318             :         }
    1319             : 
    1320         668 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
    1321             :         {
    1322           1 :             const OGRGeometryCollection *poGC = poGeom->toGeometryCollection();
    1323           1 :             bool bIsMultiPatchCompatible = false;
    1324           2 :             for (int iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++)
    1325             :             {
    1326             :                 OGRwkbGeometryType eSubGeomType =
    1327           1 :                     wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType());
    1328           1 :                 if (eSubGeomType == wkbTIN ||
    1329             :                     eSubGeomType == wkbPolyhedralSurface)
    1330             :                 {
    1331           1 :                     bIsMultiPatchCompatible = true;
    1332             :                 }
    1333           0 :                 else if (eSubGeomType != wkbMultiPolygon)
    1334             :                 {
    1335           0 :                     bIsMultiPatchCompatible = false;
    1336           0 :                     break;
    1337             :                 }
    1338             :             }
    1339           1 :             if (bIsMultiPatchCompatible)
    1340             :             {
    1341           1 :                 nShapeType = SHPT_MULTIPATCH;
    1342           1 :                 m_eRequestedGeomType = wkbUnknown;
    1343             :             }
    1344             :         }
    1345             : 
    1346         668 :         if (nShapeType != -1)
    1347             :         {
    1348         668 :             whileUnsealing(m_poFeatureDefn)->SetGeomType(m_eRequestedGeomType);
    1349         668 :             ResetGeomType(nShapeType);
    1350             :         }
    1351             :     }
    1352             : 
    1353       66718 :     const OGRErr eErr = SHPWriteOGRFeature(
    1354             :         m_hSHP, m_hDBF, m_poFeatureDefn, poFeature, m_osEncoding,
    1355       66718 :         &m_bTruncationWarningEmitted, m_bRewindOnWrite);
    1356             : 
    1357       66718 :     if (m_hSHP != nullptr)
    1358       64592 :         m_nTotalShapeCount = m_hSHP->nRecords;
    1359        2126 :     else if (m_hDBF != nullptr)
    1360        2126 :         m_nTotalShapeCount = m_hDBF->nRecords;
    1361             : #ifdef DEBUG
    1362             :     else  // Silence coverity.
    1363           0 :         CPLError(CE_Fatal, CPLE_AssertionFailed,
    1364             :                  "Should not happen: Both m_hSHP and m_hDBF are nullptrs");
    1365             : #endif
    1366             : 
    1367       66718 :     return eErr;
    1368             : }
    1369             : 
    1370             : /************************************************************************/
    1371             : /*               GetFeatureCountWithSpatialFilterOnly()                 */
    1372             : /*                                                                      */
    1373             : /* Specialized implementation of GetFeatureCount() when there is *only* */
    1374             : /* a spatial filter and no attribute filter.                            */
    1375             : /************************************************************************/
    1376             : 
    1377          37 : int OGRShapeLayer::GetFeatureCountWithSpatialFilterOnly()
    1378             : 
    1379             : {
    1380             :     /* -------------------------------------------------------------------- */
    1381             :     /*      Collect a matching list if we have attribute or spatial         */
    1382             :     /*      indices.  Only do this on the first request for a given pass    */
    1383             :     /*      of course.                                                      */
    1384             :     /* -------------------------------------------------------------------- */
    1385          37 :     if (m_panMatchingFIDs == nullptr)
    1386             :     {
    1387          37 :         ScanIndices();
    1388             :     }
    1389             : 
    1390          37 :     int nFeatureCount = 0;
    1391          37 :     int iLocalMatchingFID = 0;
    1392          37 :     int iLocalNextShapeId = 0;
    1393          37 :     bool bExpectPoints = false;
    1394             : 
    1395          37 :     if (wkbFlatten(m_poFeatureDefn->GetGeomType()) == wkbPoint)
    1396          18 :         bExpectPoints = true;
    1397             : 
    1398             :     /* -------------------------------------------------------------------- */
    1399             :     /*      Loop till we find a feature matching our criteria.              */
    1400             :     /* -------------------------------------------------------------------- */
    1401             : 
    1402             :     SHPObject sShape;
    1403          37 :     memset(&sShape, 0, sizeof(sShape));
    1404             : 
    1405             :     while (true)
    1406             :     {
    1407       12546 :         int iShape = -1;
    1408             : 
    1409       12546 :         if (m_panMatchingFIDs != nullptr)
    1410             :         {
    1411       12416 :             iShape = static_cast<int>(m_panMatchingFIDs[iLocalMatchingFID]);
    1412       12416 :             if (iShape == OGRNullFID)
    1413          25 :                 break;
    1414       12391 :             iLocalMatchingFID++;
    1415             :         }
    1416             :         else
    1417             :         {
    1418         130 :             if (iLocalNextShapeId >= m_nTotalShapeCount)
    1419          12 :                 break;
    1420         118 :             iShape = iLocalNextShapeId++;
    1421             : 
    1422         118 :             if (m_hDBF)
    1423             :             {
    1424         118 :                 if (DBFIsRecordDeleted(m_hDBF, iShape))
    1425           0 :                     continue;
    1426             : 
    1427         236 :                 if (VSIFEofL(VSI_SHP_GetVSIL(m_hDBF->fp)) ||
    1428         118 :                     VSIFErrorL(VSI_SHP_GetVSIL(m_hDBF->fp)))
    1429           0 :                     break;
    1430             :             }
    1431             :         }
    1432             : 
    1433             :         // Read full shape for point layers.
    1434       12509 :         SHPObject *psShape = nullptr;
    1435       12509 :         if (bExpectPoints ||
    1436       12445 :             m_hSHP->panRecOffset[iShape] == 0 /* lazy shx loading case */)
    1437          64 :             psShape = SHPReadObject(m_hSHP, iShape);
    1438             : 
    1439             :         /* --------------------------------------------------------------------
    1440             :          */
    1441             :         /*      Only read feature type and bounding box for now. In case of */
    1442             :         /*      inconclusive tests on bounding box only, we will read the full
    1443             :          */
    1444             :         /*      shape later. */
    1445             :         /* --------------------------------------------------------------------
    1446             :          */
    1447       12445 :         else if (iShape >= 0 && iShape < m_hSHP->nRecords &&
    1448       12445 :                  m_hSHP->panRecSize[iShape] > 4 + 8 * 4)
    1449             :         {
    1450       12445 :             GByte abyBuf[4 + 8 * 4] = {};
    1451       37335 :             if (m_hSHP->sHooks.FSeek(
    1452       24890 :                     m_hSHP->fpSHP, m_hSHP->panRecOffset[iShape] + 8, 0) == 0 &&
    1453       12445 :                 m_hSHP->sHooks.FRead(abyBuf, sizeof(abyBuf), 1,
    1454       12445 :                                      m_hSHP->fpSHP) == 1)
    1455             :             {
    1456       12445 :                 memcpy(&(sShape.nSHPType), abyBuf, 4);
    1457       12445 :                 CPL_LSBPTR32(&(sShape.nSHPType));
    1458       12445 :                 if (sShape.nSHPType != SHPT_NULL &&
    1459       12445 :                     sShape.nSHPType != SHPT_POINT &&
    1460       12445 :                     sShape.nSHPType != SHPT_POINTM &&
    1461       12445 :                     sShape.nSHPType != SHPT_POINTZ)
    1462             :                 {
    1463       12445 :                     psShape = &sShape;
    1464       12445 :                     memcpy(&(sShape.dfXMin), abyBuf + 4, 8);
    1465       12445 :                     memcpy(&(sShape.dfYMin), abyBuf + 12, 8);
    1466       12445 :                     memcpy(&(sShape.dfXMax), abyBuf + 20, 8);
    1467       12445 :                     memcpy(&(sShape.dfYMax), abyBuf + 28, 8);
    1468       12445 :                     CPL_LSBPTR64(&(sShape.dfXMin));
    1469       12445 :                     CPL_LSBPTR64(&(sShape.dfYMin));
    1470       12445 :                     CPL_LSBPTR64(&(sShape.dfXMax));
    1471       12445 :                     CPL_LSBPTR64(&(sShape.dfYMax));
    1472             :                 }
    1473             :             }
    1474             :             else
    1475             :             {
    1476           0 :                 break;
    1477             :             }
    1478             :         }
    1479             : 
    1480       12509 :         if (psShape != nullptr && psShape->nSHPType != SHPT_NULL)
    1481             :         {
    1482       12509 :             OGRGeometry *poGeometry = nullptr;
    1483       12509 :             OGREnvelope sGeomEnv;
    1484             :             // Test if we have a degenerated bounding box.
    1485       12509 :             if (psShape->nSHPType != SHPT_POINT &&
    1486       12445 :                 psShape->nSHPType != SHPT_POINTZ &&
    1487       12445 :                 psShape->nSHPType != SHPT_POINTM &&
    1488       12445 :                 (psShape->dfXMin == psShape->dfXMax ||
    1489       12445 :                  psShape->dfYMin == psShape->dfYMax))
    1490             :             {
    1491             :                 // Need to read the full geometry to compute the envelope.
    1492           0 :                 if (psShape == &sShape)
    1493           0 :                     psShape = SHPReadObject(m_hSHP, iShape);
    1494             : 
    1495           0 :                 if (psShape)
    1496             :                 {
    1497           0 :                     poGeometry = SHPReadOGRObject(
    1498           0 :                         m_hSHP, iShape, psShape, m_bHasWarnedWrongWindingOrder);
    1499           0 :                     if (poGeometry)
    1500           0 :                         poGeometry->getEnvelope(&sGeomEnv);
    1501           0 :                     psShape = nullptr;
    1502             :                 }
    1503             :             }
    1504             :             else
    1505             :             {
    1506             :                 // Trust the shape bounding box as the shape envelope.
    1507       12509 :                 sGeomEnv.MinX = psShape->dfXMin;
    1508       12509 :                 sGeomEnv.MinY = psShape->dfYMin;
    1509       12509 :                 sGeomEnv.MaxX = psShape->dfXMax;
    1510       12509 :                 sGeomEnv.MaxY = psShape->dfYMax;
    1511             :             }
    1512             : 
    1513             :             /* --------------------------------------------------------------------
    1514             :              */
    1515             :             /*      If there is no */
    1516             :             /*      intersection between the envelopes we are sure not to have
    1517             :              */
    1518             :             /*      any intersection. */
    1519             :             /* --------------------------------------------------------------------
    1520             :              */
    1521       12509 :             if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
    1522       12483 :                 sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
    1523       12482 :                 m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
    1524       12446 :                 m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
    1525             :             {
    1526             :             }
    1527             :             /* --------------------------------------------------------------------
    1528             :              */
    1529             :             /*      If the filter geometry is its own envelope and if the */
    1530             :             /*      envelope of the geometry is inside the filter geometry, */
    1531             :             /*      the geometry itself is inside the filter geometry */
    1532             :             /* --------------------------------------------------------------------
    1533             :              */
    1534       12411 :             else if (m_bFilterIsEnvelope &&
    1535       12411 :                      sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
    1536       12253 :                      sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
    1537       12104 :                      sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
    1538       11981 :                      sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
    1539             :             {
    1540       11856 :                 nFeatureCount++;
    1541             :             }
    1542             :             else
    1543             :             {
    1544             :                 /* --------------------------------------------------------------------
    1545             :                  */
    1546             :                 /*      Fallback to full intersect test (using GEOS) if we still
    1547             :                  */
    1548             :                 /*      don't know for sure. */
    1549             :                 /* --------------------------------------------------------------------
    1550             :                  */
    1551         555 :                 if (OGRGeometryFactory::haveGEOS())
    1552             :                 {
    1553             :                     // Read the full geometry.
    1554         555 :                     if (poGeometry == nullptr)
    1555             :                     {
    1556         555 :                         if (psShape == &sShape)
    1557         555 :                             psShape = SHPReadObject(m_hSHP, iShape);
    1558         555 :                         if (psShape)
    1559             :                         {
    1560             :                             poGeometry =
    1561        1110 :                                 SHPReadOGRObject(m_hSHP, iShape, psShape,
    1562         555 :                                                  m_bHasWarnedWrongWindingOrder);
    1563         555 :                             psShape = nullptr;
    1564             :                         }
    1565             :                     }
    1566         555 :                     if (poGeometry == nullptr)
    1567             :                     {
    1568           0 :                         nFeatureCount++;
    1569             :                     }
    1570         555 :                     else if (m_pPreparedFilterGeom != nullptr)
    1571             :                     {
    1572         555 :                         if (OGRPreparedGeometryIntersects(
    1573             :                                 m_pPreparedFilterGeom,
    1574         555 :                                 OGRGeometry::ToHandle(poGeometry)))
    1575             :                         {
    1576         550 :                             nFeatureCount++;
    1577             :                         }
    1578             :                     }
    1579           0 :                     else if (m_poFilterGeom->Intersects(poGeometry))
    1580           0 :                         nFeatureCount++;
    1581             :                 }
    1582             :                 else
    1583             :                 {
    1584           0 :                     nFeatureCount++;
    1585             :                 }
    1586             :             }
    1587             : 
    1588       12509 :             delete poGeometry;
    1589             :         }
    1590             :         else
    1591             :         {
    1592           0 :             nFeatureCount++;
    1593             :         }
    1594             : 
    1595       12509 :         if (psShape && psShape != &sShape)
    1596          64 :             SHPDestroyObject(psShape);
    1597       12509 :     }
    1598             : 
    1599          37 :     return nFeatureCount;
    1600             : }
    1601             : 
    1602             : /************************************************************************/
    1603             : /*                          GetFeatureCount()                           */
    1604             : /************************************************************************/
    1605             : 
    1606         683 : GIntBig OGRShapeLayer::GetFeatureCount(int bForce)
    1607             : 
    1608             : {
    1609             :     // Check if the spatial filter is non-trivial.
    1610         683 :     bool bHasTrivialSpatialFilter = false;
    1611         683 :     if (m_poFilterGeom != nullptr)
    1612             :     {
    1613          50 :         OGREnvelope oSpatialFilterEnvelope;
    1614          50 :         m_poFilterGeom->getEnvelope(&oSpatialFilterEnvelope);
    1615             : 
    1616          50 :         OGREnvelope oLayerExtent;
    1617          50 :         if (GetExtent(&oLayerExtent, TRUE) == OGRERR_NONE)
    1618             :         {
    1619          50 :             if (oSpatialFilterEnvelope.Contains(oLayerExtent))
    1620             :             {
    1621           0 :                 bHasTrivialSpatialFilter = true;
    1622             :             }
    1623             :             else
    1624             :             {
    1625          50 :                 bHasTrivialSpatialFilter = false;
    1626             :             }
    1627             :         }
    1628             :         else
    1629             :         {
    1630           0 :             bHasTrivialSpatialFilter = false;
    1631             :         }
    1632             :     }
    1633             :     else
    1634             :     {
    1635         633 :         bHasTrivialSpatialFilter = true;
    1636             :     }
    1637             : 
    1638         683 :     if (bHasTrivialSpatialFilter && m_poAttrQuery == nullptr)
    1639         585 :         return m_nTotalShapeCount;
    1640             : 
    1641          98 :     if (!TouchLayer())
    1642           0 :         return 0;
    1643             : 
    1644             :     // Spatial filter only.
    1645          98 :     if (m_poAttrQuery == nullptr && m_hSHP != nullptr)
    1646             :     {
    1647          37 :         return GetFeatureCountWithSpatialFilterOnly();
    1648             :     }
    1649             : 
    1650             :     // Attribute filter only.
    1651          61 :     if (m_poAttrQuery != nullptr && m_poFilterGeom == nullptr)
    1652             :     {
    1653             :         // See if we can ignore reading geometries.
    1654             :         const bool bSaveGeometryIgnored =
    1655          48 :             CPL_TO_BOOL(m_poFeatureDefn->IsGeometryIgnored());
    1656          48 :         if (!AttributeFilterEvaluationNeedsGeometry())
    1657          48 :             m_poFeatureDefn->SetGeometryIgnored(TRUE);
    1658             : 
    1659          48 :         GIntBig nRet = OGRLayer::GetFeatureCount(bForce);
    1660             : 
    1661          48 :         m_poFeatureDefn->SetGeometryIgnored(bSaveGeometryIgnored);
    1662          48 :         return nRet;
    1663             :     }
    1664             : 
    1665          13 :     return OGRLayer::GetFeatureCount(bForce);
    1666             : }
    1667             : 
    1668             : /************************************************************************/
    1669             : /*                            IGetExtent()                              */
    1670             : /*                                                                      */
    1671             : /*      Fetch extent of the data currently stored in the dataset.       */
    1672             : /*      The bForce flag has no effect on SHP files since that value     */
    1673             : /*      is always in the header.                                        */
    1674             : /*                                                                      */
    1675             : /*      Returns OGRERR_NONE/OGRRERR_FAILURE.                            */
    1676             : /************************************************************************/
    1677             : 
    1678       13159 : OGRErr OGRShapeLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
    1679             :                                  bool bForce)
    1680             : 
    1681             : {
    1682       13159 :     if (!TouchLayer())
    1683           0 :         return OGRERR_FAILURE;
    1684             : 
    1685       13159 :     if (m_hSHP == nullptr)
    1686           0 :         return OGRERR_FAILURE;
    1687             : 
    1688       13159 :     double adMin[4] = {0.0, 0.0, 0.0, 0.0};
    1689       13159 :     double adMax[4] = {0.0, 0.0, 0.0, 0.0};
    1690             : 
    1691       13159 :     SHPGetInfo(m_hSHP, nullptr, nullptr, adMin, adMax);
    1692             : 
    1693       13159 :     psExtent->MinX = adMin[0];
    1694       13159 :     psExtent->MinY = adMin[1];
    1695       13159 :     psExtent->MaxX = adMax[0];
    1696       13159 :     psExtent->MaxY = adMax[1];
    1697             : 
    1698       26316 :     if (std::isnan(adMin[0]) || std::isnan(adMin[1]) || std::isnan(adMax[0]) ||
    1699       13157 :         std::isnan(adMax[1]))
    1700             :     {
    1701           2 :         CPLDebug("SHAPE", "Invalid extent in shape header");
    1702             : 
    1703             :         // Disable filters to avoid infinite recursion in GetNextFeature()
    1704             :         // that calls ScanIndices() that call GetExtent.
    1705           2 :         OGRFeatureQuery *poAttrQuery = m_poAttrQuery;
    1706           2 :         m_poAttrQuery = nullptr;
    1707           2 :         OGRGeometry *poFilterGeom = m_poFilterGeom;
    1708           2 :         m_poFilterGeom = nullptr;
    1709             : 
    1710           2 :         psExtent->MinX = 0;
    1711           2 :         psExtent->MinY = 0;
    1712           2 :         psExtent->MaxX = 0;
    1713           2 :         psExtent->MaxY = 0;
    1714             : 
    1715           2 :         const OGRErr eErr = OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
    1716             : 
    1717           2 :         m_poAttrQuery = poAttrQuery;
    1718           2 :         m_poFilterGeom = poFilterGeom;
    1719           2 :         return eErr;
    1720             :     }
    1721             : 
    1722       13157 :     return OGRERR_NONE;
    1723             : }
    1724             : 
    1725           4 : OGRErr OGRShapeLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
    1726             :                                    bool bForce)
    1727             : {
    1728           4 :     if (m_poFilterGeom || m_poAttrQuery)
    1729           0 :         return OGRLayer::IGetExtent3D(iGeomField, psExtent3D, bForce);
    1730             : 
    1731           4 :     if (!TouchLayer())
    1732           0 :         return OGRERR_FAILURE;
    1733             : 
    1734           4 :     if (m_hSHP == nullptr)
    1735           0 :         return OGRERR_FAILURE;
    1736             : 
    1737           4 :     double adMin[4] = {0.0, 0.0, 0.0, 0.0};
    1738           4 :     double adMax[4] = {0.0, 0.0, 0.0, 0.0};
    1739             : 
    1740           4 :     SHPGetInfo(m_hSHP, nullptr, nullptr, adMin, adMax);
    1741             : 
    1742           4 :     psExtent3D->MinX = adMin[0];
    1743           4 :     psExtent3D->MinY = adMin[1];
    1744           4 :     psExtent3D->MaxX = adMax[0];
    1745           4 :     psExtent3D->MaxY = adMax[1];
    1746             : 
    1747           4 :     if (OGR_GT_HasZ(m_poFeatureDefn->GetGeomType()))
    1748             :     {
    1749           1 :         psExtent3D->MinZ = adMin[2];
    1750           1 :         psExtent3D->MaxZ = adMax[2];
    1751             :     }
    1752             :     else
    1753             :     {
    1754           3 :         psExtent3D->MinZ = std::numeric_limits<double>::infinity();
    1755           3 :         psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
    1756             :     }
    1757             : 
    1758           8 :     if (std::isnan(adMin[0]) || std::isnan(adMin[1]) || std::isnan(adMax[0]) ||
    1759           4 :         std::isnan(adMax[1]))
    1760             :     {
    1761           0 :         CPLDebug("SHAPE", "Invalid extent in shape header");
    1762             : 
    1763             :         // Disable filters to avoid infinite recursion in GetNextFeature()
    1764             :         // that calls ScanIndices() that call GetExtent.
    1765           0 :         OGRFeatureQuery *poAttrQuery = m_poAttrQuery;
    1766           0 :         m_poAttrQuery = nullptr;
    1767           0 :         OGRGeometry *poFilterGeom = m_poFilterGeom;
    1768           0 :         m_poFilterGeom = nullptr;
    1769             : 
    1770             :         const OGRErr eErr =
    1771           0 :             OGRLayer::IGetExtent3D(iGeomField, psExtent3D, bForce);
    1772             : 
    1773           0 :         m_poAttrQuery = poAttrQuery;
    1774           0 :         m_poFilterGeom = poFilterGeom;
    1775           0 :         return eErr;
    1776             :     }
    1777             : 
    1778           4 :     return OGRERR_NONE;
    1779             : }
    1780             : 
    1781             : /************************************************************************/
    1782             : /*                           TestCapability()                           */
    1783             : /************************************************************************/
    1784             : 
    1785       12201 : int OGRShapeLayer::TestCapability(const char *pszCap) const
    1786             : 
    1787             : {
    1788       12201 :     if (!const_cast<OGRShapeLayer *>(this)->TouchLayer())
    1789           0 :         return FALSE;
    1790             : 
    1791       12201 :     if (EQUAL(pszCap, OLCRandomRead))
    1792          11 :         return TRUE;
    1793             : 
    1794       12190 :     if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite))
    1795          31 :         return m_bUpdateAccess;
    1796             : 
    1797       12159 :     if (EQUAL(pszCap, OLCFastFeatureCount))
    1798             :     {
    1799         270 :         if (!(m_poFilterGeom == nullptr ||
    1800          31 :               const_cast<OGRShapeLayer *>(this)->CheckForQIX() ||
    1801          14 :               const_cast<OGRShapeLayer *>(this)->CheckForSBN()))
    1802          14 :             return FALSE;
    1803             : 
    1804         225 :         if (m_poAttrQuery != nullptr)
    1805             :         {
    1806          36 :             const_cast<OGRShapeLayer *>(this)->InitializeIndexSupport(
    1807             :                 m_osFullName.c_str());
    1808          36 :             return m_poAttrQuery->CanUseIndex(
    1809          36 :                 const_cast<OGRShapeLayer *>(this));
    1810             :         }
    1811         189 :         return TRUE;
    1812             :     }
    1813             : 
    1814       11920 :     if (EQUAL(pszCap, OLCDeleteFeature))
    1815           3 :         return m_bUpdateAccess;
    1816             : 
    1817       11917 :     if (EQUAL(pszCap, OLCFastSpatialFilter))
    1818           6 :         return const_cast<OGRShapeLayer *>(this)->CheckForQIX() ||
    1819           6 :                const_cast<OGRShapeLayer *>(this)->CheckForSBN();
    1820             : 
    1821       11911 :     if (EQUAL(pszCap, OLCFastGetExtent))
    1822          35 :         return TRUE;
    1823             : 
    1824       11876 :     if (EQUAL(pszCap, OLCFastGetExtent3D))
    1825           2 :         return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr;
    1826             : 
    1827       11874 :     if (EQUAL(pszCap, OLCFastSetNextByIndex))
    1828          13 :         return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr;
    1829             : 
    1830       11861 :     if (EQUAL(pszCap, OLCCreateField))
    1831          19 :         return m_bUpdateAccess;
    1832             : 
    1833       11842 :     if (EQUAL(pszCap, OLCDeleteField))
    1834           6 :         return m_bUpdateAccess;
    1835             : 
    1836       11836 :     if (EQUAL(pszCap, OLCReorderFields))
    1837           6 :         return m_bUpdateAccess;
    1838             : 
    1839       11830 :     if (EQUAL(pszCap, OLCAlterFieldDefn) ||
    1840       11824 :         EQUAL(pszCap, OLCAlterGeomFieldDefn))
    1841           7 :         return m_bUpdateAccess;
    1842             : 
    1843       11823 :     if (EQUAL(pszCap, OLCRename))
    1844           9 :         return m_bUpdateAccess;
    1845             : 
    1846       11814 :     if (EQUAL(pszCap, OLCIgnoreFields))
    1847         743 :         return TRUE;
    1848             : 
    1849       11071 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
    1850             :     {
    1851             :         // No encoding defined: we don't know.
    1852        7107 :         if (m_osEncoding.empty())
    1853         471 :             return FALSE;
    1854             : 
    1855        6636 :         if (m_hDBF == nullptr || DBFGetFieldCount(m_hDBF) == 0)
    1856        1726 :             return TRUE;
    1857             : 
    1858             :         // Otherwise test that we can re-encode field names to UTF-8.
    1859        4910 :         const int nFieldCount = DBFGetFieldCount(m_hDBF);
    1860       13210 :         for (int i = 0; i < nFieldCount; i++)
    1861             :         {
    1862        8301 :             char szFieldName[XBASE_FLDNAME_LEN_READ + 1] = {};
    1863        8301 :             int nWidth = 0;
    1864        8301 :             int nPrecision = 0;
    1865             : 
    1866        8301 :             DBFGetFieldInfo(m_hDBF, i, szFieldName, &nWidth, &nPrecision);
    1867             : 
    1868        8301 :             if (!CPLCanRecode(szFieldName, m_osEncoding, CPL_ENC_UTF8))
    1869             :             {
    1870           1 :                 return FALSE;
    1871             :             }
    1872             :         }
    1873             : 
    1874        4909 :         return TRUE;
    1875             :     }
    1876             : 
    1877        3964 :     if (EQUAL(pszCap, OLCMeasuredGeometries))
    1878        1730 :         return TRUE;
    1879             : 
    1880        2234 :     if (EQUAL(pszCap, OLCZGeometries))
    1881          30 :         return TRUE;
    1882             : 
    1883        2204 :     return FALSE;
    1884             : }
    1885             : 
    1886             : /************************************************************************/
    1887             : /*                            CreateField()                             */
    1888             : /************************************************************************/
    1889             : 
    1890        5056 : OGRErr OGRShapeLayer::CreateField(const OGRFieldDefn *poFieldDefn,
    1891             :                                   int bApproxOK)
    1892             : 
    1893             : {
    1894        5056 :     if (!StartUpdate("CreateField"))
    1895           1 :         return OGRERR_FAILURE;
    1896             : 
    1897        5055 :     CPLAssert(nullptr != poFieldDefn);
    1898             : 
    1899        5055 :     bool bDBFJustCreated = false;
    1900        5055 :     if (m_hDBF == nullptr)
    1901             :     {
    1902             :         const CPLString osFilename =
    1903           1 :             CPLResetExtensionSafe(m_osFullName.c_str(), "dbf");
    1904           1 :         m_hDBF = DBFCreate(osFilename);
    1905             : 
    1906           1 :         if (m_hDBF == nullptr)
    1907             :         {
    1908           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1909             :                      "Failed to create DBF file `%s'.", osFilename.c_str());
    1910           0 :             return OGRERR_FAILURE;
    1911             :         }
    1912             : 
    1913           1 :         bDBFJustCreated = true;
    1914             :     }
    1915             : 
    1916        5055 :     if (m_hDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535)
    1917             :     {
    1918           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1919             :                  "Cannot add field %s. Header length limit reached "
    1920             :                  "(max 65535 bytes, 2046 fields).",
    1921             :                  poFieldDefn->GetNameRef());
    1922           1 :         return OGRERR_FAILURE;
    1923             :     }
    1924             : 
    1925        5054 :     CPLErrorReset();
    1926             : 
    1927        5054 :     if (m_poFeatureDefn->GetFieldCount() == 255)
    1928             :     {
    1929           2 :         CPLError(CE_Warning, CPLE_AppDefined,
    1930             :                  "Creating a 256th field, "
    1931             :                  "but some DBF readers might only support 255 fields");
    1932             :     }
    1933             : 
    1934             :     /* -------------------------------------------------------------------- */
    1935             :     /*      Normalize field name                                            */
    1936             :     /* -------------------------------------------------------------------- */
    1937       10108 :     CPLString osFieldName;
    1938        5054 :     if (!m_osEncoding.empty())
    1939             :     {
    1940        5053 :         CPLClearRecodeWarningFlags();
    1941        5053 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1942        5053 :         CPLErr eLastErr = CPLGetLastErrorType();
    1943             :         char *const pszRecoded =
    1944        5053 :             CPLRecode(poFieldDefn->GetNameRef(), CPL_ENC_UTF8, m_osEncoding);
    1945        5053 :         CPLPopErrorHandler();
    1946        5053 :         osFieldName = pszRecoded;
    1947        5053 :         CPLFree(pszRecoded);
    1948        5053 :         if (CPLGetLastErrorType() != eLastErr)
    1949             :         {
    1950           1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1951             :                      "Failed to create field name '%s': cannot convert to %s",
    1952             :                      poFieldDefn->GetNameRef(), m_osEncoding.c_str());
    1953           1 :             return OGRERR_FAILURE;
    1954             :         }
    1955             :     }
    1956             :     else
    1957             :     {
    1958           1 :         osFieldName = poFieldDefn->GetNameRef();
    1959             :     }
    1960             : 
    1961        5053 :     const int nNameSize = static_cast<int>(osFieldName.size());
    1962             :     char szNewFieldName[XBASE_FLDNAME_LEN_WRITE + 1];
    1963       10106 :     CPLString osRadixFieldName;
    1964       10106 :     CPLString osRadixFieldNameUC;
    1965             :     {
    1966        5053 :         char *pszTmp = CPLScanString(
    1967        5053 :             osFieldName, std::min(nNameSize, XBASE_FLDNAME_LEN_WRITE), TRUE,
    1968             :             TRUE);
    1969        5053 :         strncpy(szNewFieldName, pszTmp, sizeof(szNewFieldName) - 1);
    1970        5053 :         szNewFieldName[sizeof(szNewFieldName) - 1] = '\0';
    1971        5053 :         osRadixFieldName = pszTmp;
    1972        5053 :         osRadixFieldNameUC = CPLString(osRadixFieldName).toupper();
    1973        5053 :         CPLFree(pszTmp);
    1974             :     }
    1975             : 
    1976       10106 :     CPLString osNewFieldNameUC(szNewFieldName);
    1977        5053 :     osNewFieldNameUC.toupper();
    1978             : 
    1979        5053 :     if (m_oSetUCFieldName.empty())
    1980             :     {
    1981        1414 :         for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
    1982             :         {
    1983             :             m_oSetUCFieldName.insert(
    1984          18 :                 CPLString(m_poFeatureDefn->GetFieldDefn(i)->GetNameRef())
    1985          18 :                     .toupper());
    1986             :         }
    1987             :     }
    1988             : 
    1989             :     bool bFoundFieldName =
    1990        5053 :         m_oSetUCFieldName.find(osNewFieldNameUC) != m_oSetUCFieldName.end();
    1991             : 
    1992        5053 :     if (!bApproxOK && (bFoundFieldName || !EQUAL(osFieldName, szNewFieldName)))
    1993             :     {
    1994           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1995             :                  "Failed to add field named '%s'", poFieldDefn->GetNameRef());
    1996             : 
    1997           0 :         return OGRERR_FAILURE;
    1998             :     }
    1999             : 
    2000        5053 :     if (bFoundFieldName)
    2001             :     {
    2002          36 :         int nRenameNum = 1;
    2003         213 :         while (bFoundFieldName && nRenameNum < 10)
    2004             :         {
    2005         177 :             CPLsnprintf(szNewFieldName, sizeof(szNewFieldName), "%.8s_%.1d",
    2006             :                         osRadixFieldName.c_str(), nRenameNum);
    2007             :             osNewFieldNameUC.Printf("%.8s_%.1d", osRadixFieldNameUC.c_str(),
    2008         177 :                                     nRenameNum);
    2009         177 :             bFoundFieldName = m_oSetUCFieldName.find(osNewFieldNameUC) !=
    2010         177 :                               m_oSetUCFieldName.end();
    2011         177 :             nRenameNum++;
    2012             :         }
    2013             : 
    2014          41 :         while (bFoundFieldName && nRenameNum < 100)
    2015             :         {
    2016           5 :             CPLsnprintf(szNewFieldName, sizeof(szNewFieldName), "%.8s%.2d",
    2017             :                         osRadixFieldName.c_str(), nRenameNum);
    2018             :             osNewFieldNameUC.Printf("%.8s%.2d", osRadixFieldNameUC.c_str(),
    2019           5 :                                     nRenameNum);
    2020           5 :             bFoundFieldName = m_oSetUCFieldName.find(osNewFieldNameUC) !=
    2021           5 :                               m_oSetUCFieldName.end();
    2022           5 :             nRenameNum++;
    2023             :         }
    2024             : 
    2025          36 :         if (bFoundFieldName)
    2026             :         {
    2027             :             // One hundred similar field names!!?
    2028           0 :             CPLError(
    2029             :                 CE_Failure, CPLE_NotSupported,
    2030             :                 "Too many field names like '%s' when truncated to %d letters "
    2031             :                 "for Shapefile format.",
    2032             :                 poFieldDefn->GetNameRef(), XBASE_FLDNAME_LEN_WRITE);
    2033           0 :             return OGRERR_FAILURE;
    2034             :         }
    2035             :     }
    2036             : 
    2037       10106 :     OGRFieldDefn oModFieldDefn(poFieldDefn);
    2038             : 
    2039        5053 :     if (!EQUAL(osFieldName, szNewFieldName))
    2040             :     {
    2041          58 :         CPLError(CE_Warning, CPLE_NotSupported,
    2042             :                  "Normalized/laundered field name: '%s' to '%s'",
    2043             :                  poFieldDefn->GetNameRef(), szNewFieldName);
    2044             : 
    2045             :         // Set field name with normalized value.
    2046          58 :         oModFieldDefn.SetName(szNewFieldName);
    2047             :     }
    2048             : 
    2049             :     /* -------------------------------------------------------------------- */
    2050             :     /*      Add field to layer                                              */
    2051             :     /* -------------------------------------------------------------------- */
    2052        5053 :     char chType = 'C';
    2053        5053 :     int nWidth = 0;
    2054        5053 :     int nDecimals = 0;
    2055             : 
    2056        5053 :     switch (oModFieldDefn.GetType())
    2057             :     {
    2058        2225 :         case OFTInteger:
    2059        2225 :             if (oModFieldDefn.GetSubType() == OFSTBoolean)
    2060             :             {
    2061           2 :                 chType = 'L';
    2062           2 :                 nWidth = 1;
    2063             :             }
    2064             :             else
    2065             :             {
    2066        2223 :                 chType = 'N';
    2067        2223 :                 nWidth = oModFieldDefn.GetWidth();
    2068        2223 :                 if (nWidth == 0)
    2069        2180 :                     nWidth = 9;
    2070             :             }
    2071        2225 :             break;
    2072             : 
    2073         129 :         case OFTInteger64:
    2074         129 :             chType = 'N';
    2075         129 :             nWidth = oModFieldDefn.GetWidth();
    2076         129 :             if (nWidth == 0)
    2077          21 :                 nWidth = 18;
    2078         129 :             break;
    2079             : 
    2080         232 :         case OFTReal:
    2081         232 :             chType = 'N';
    2082         232 :             nWidth = oModFieldDefn.GetWidth();
    2083         232 :             nDecimals = oModFieldDefn.GetPrecision();
    2084         232 :             if (nWidth == 0)
    2085             :             {
    2086         132 :                 nWidth = 24;
    2087         132 :                 nDecimals = 15;
    2088             :             }
    2089         232 :             break;
    2090             : 
    2091        2430 :         case OFTString:
    2092        2430 :             chType = 'C';
    2093        2430 :             nWidth = oModFieldDefn.GetWidth();
    2094        2430 :             if (nWidth == 0)
    2095        2259 :                 nWidth = 80;
    2096         171 :             else if (nWidth > OGR_DBF_MAX_FIELD_WIDTH)
    2097             :             {
    2098           1 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2099             :                          "Field %s of width %d truncated to %d.",
    2100             :                          szNewFieldName, nWidth, OGR_DBF_MAX_FIELD_WIDTH);
    2101           1 :                 nWidth = OGR_DBF_MAX_FIELD_WIDTH;
    2102             :             }
    2103        2430 :             break;
    2104             : 
    2105          21 :         case OFTDate:
    2106          21 :             chType = 'D';
    2107          21 :             nWidth = 8;
    2108          21 :             break;
    2109             : 
    2110          16 :         case OFTDateTime:
    2111          16 :             CPLError(
    2112             :                 CE_Warning, CPLE_NotSupported,
    2113             :                 "Field %s created as String field, though DateTime requested.",
    2114             :                 szNewFieldName);
    2115          16 :             chType = 'C';
    2116          16 :             nWidth = static_cast<int>(strlen("YYYY-MM-DDTHH:MM:SS.sss+HH:MM"));
    2117          16 :             oModFieldDefn.SetType(OFTString);
    2118          16 :             break;
    2119             : 
    2120           0 :         default:
    2121           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2122             :                      "Can't create fields of type %s on shapefile layers.",
    2123             :                      OGRFieldDefn::GetFieldTypeName(oModFieldDefn.GetType()));
    2124             : 
    2125           0 :             return OGRERR_FAILURE;
    2126             :     }
    2127             : 
    2128        5053 :     oModFieldDefn.SetWidth(nWidth);
    2129        5053 :     oModFieldDefn.SetPrecision(nDecimals);
    2130             : 
    2131             :     // Suppress the dummy FID field if we have created it just before.
    2132        5053 :     if (DBFGetFieldCount(m_hDBF) == 1 && m_poFeatureDefn->GetFieldCount() == 0)
    2133             :     {
    2134           3 :         DBFDeleteField(m_hDBF, 0);
    2135             :     }
    2136             : 
    2137        5053 :     const int iNewField = DBFAddNativeFieldType(m_hDBF, szNewFieldName, chType,
    2138             :                                                 nWidth, nDecimals);
    2139             : 
    2140        5053 :     if (iNewField != -1)
    2141             :     {
    2142        5052 :         m_oSetUCFieldName.insert(std::move(osNewFieldNameUC));
    2143             : 
    2144        5052 :         whileUnsealing(m_poFeatureDefn)->AddFieldDefn(&oModFieldDefn);
    2145             : 
    2146        5052 :         if (bDBFJustCreated)
    2147             :         {
    2148           2 :             for (int i = 0; i < m_nTotalShapeCount; i++)
    2149             :             {
    2150           1 :                 DBFWriteNULLAttribute(m_hDBF, i, 0);
    2151             :             }
    2152             :         }
    2153             : 
    2154        5052 :         return OGRERR_NONE;
    2155             :     }
    2156             : 
    2157           1 :     CPLError(CE_Failure, CPLE_AppDefined,
    2158             :              "Can't create field %s in Shape DBF file, reason unknown.",
    2159             :              szNewFieldName);
    2160             : 
    2161           1 :     return OGRERR_FAILURE;
    2162             : }
    2163             : 
    2164             : /************************************************************************/
    2165             : /*                            DeleteField()                             */
    2166             : /************************************************************************/
    2167             : 
    2168          12 : OGRErr OGRShapeLayer::DeleteField(int iField)
    2169             : {
    2170          12 :     if (!StartUpdate("DeleteField"))
    2171           1 :         return OGRERR_FAILURE;
    2172             : 
    2173          11 :     if (iField < 0 || iField >= m_poFeatureDefn->GetFieldCount())
    2174             :     {
    2175           3 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2176           3 :         return OGRERR_FAILURE;
    2177             :     }
    2178             : 
    2179           8 :     m_oSetUCFieldName.clear();
    2180             : 
    2181           8 :     if (DBFDeleteField(m_hDBF, iField))
    2182             :     {
    2183           8 :         TruncateDBF();
    2184             : 
    2185           8 :         return whileUnsealing(m_poFeatureDefn)->DeleteFieldDefn(iField);
    2186             :     }
    2187             : 
    2188           0 :     return OGRERR_FAILURE;
    2189             : }
    2190             : 
    2191             : /************************************************************************/
    2192             : /*                           ReorderFields()                            */
    2193             : /************************************************************************/
    2194             : 
    2195          25 : OGRErr OGRShapeLayer::ReorderFields(int *panMap)
    2196             : {
    2197          25 :     if (!StartUpdate("ReorderFields"))
    2198           1 :         return OGRERR_FAILURE;
    2199             : 
    2200          24 :     if (m_poFeatureDefn->GetFieldCount() == 0)
    2201           5 :         return OGRERR_NONE;
    2202             : 
    2203          19 :     OGRErr eErr = OGRCheckPermutation(panMap, m_poFeatureDefn->GetFieldCount());
    2204          19 :     if (eErr != OGRERR_NONE)
    2205           2 :         return eErr;
    2206             : 
    2207          17 :     if (DBFReorderFields(m_hDBF, panMap))
    2208             :     {
    2209          17 :         return whileUnsealing(m_poFeatureDefn)->ReorderFieldDefns(panMap);
    2210             :     }
    2211             : 
    2212           0 :     return OGRERR_FAILURE;
    2213             : }
    2214             : 
    2215             : /************************************************************************/
    2216             : /*                           AlterFieldDefn()                           */
    2217             : /************************************************************************/
    2218             : 
    2219          21 : OGRErr OGRShapeLayer::AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
    2220             :                                      int nFlagsIn)
    2221             : {
    2222          21 :     if (!StartUpdate("AlterFieldDefn"))
    2223           1 :         return OGRERR_FAILURE;
    2224             : 
    2225          20 :     if (iField < 0 || iField >= m_poFeatureDefn->GetFieldCount())
    2226             :     {
    2227           3 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2228           3 :         return OGRERR_FAILURE;
    2229             :     }
    2230             : 
    2231          17 :     m_oSetUCFieldName.clear();
    2232             : 
    2233          17 :     OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(iField);
    2234          17 :     OGRFieldType eType = poFieldDefn->GetType();
    2235             : 
    2236          34 :     auto oTemporaryUnsealer(poFieldDefn->GetTemporaryUnsealer());
    2237             : 
    2238             :     // On reading we support up to 11 characters
    2239          17 :     char szFieldName[XBASE_FLDNAME_LEN_READ + 1] = {};
    2240          17 :     int nWidth = 0;
    2241          17 :     int nPrecision = 0;
    2242          17 :     DBFGetFieldInfo(m_hDBF, iField, szFieldName, &nWidth, &nPrecision);
    2243          17 :     char chNativeType = DBFGetNativeFieldType(m_hDBF, iField);
    2244             : 
    2245          32 :     if ((nFlagsIn & ALTER_TYPE_FLAG) &&
    2246          15 :         poNewFieldDefn->GetType() != poFieldDefn->GetType())
    2247             :     {
    2248           5 :         if (poNewFieldDefn->GetType() == OFTInteger64 &&
    2249           1 :             poFieldDefn->GetType() == OFTInteger)
    2250             :         {
    2251           1 :             eType = poNewFieldDefn->GetType();
    2252             :         }
    2253           3 :         else if (poNewFieldDefn->GetType() != OFTString)
    2254             :         {
    2255           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    2256             :                      "Can only convert to OFTString");
    2257           1 :             return OGRERR_FAILURE;
    2258             :         }
    2259             :         else
    2260             :         {
    2261           2 :             chNativeType = 'C';
    2262           2 :             eType = poNewFieldDefn->GetType();
    2263             :         }
    2264             :     }
    2265             : 
    2266          16 :     if (nFlagsIn & ALTER_NAME_FLAG)
    2267             :     {
    2268          15 :         CPLString osFieldName;
    2269          15 :         if (!m_osEncoding.empty())
    2270             :         {
    2271          15 :             CPLClearRecodeWarningFlags();
    2272          15 :             CPLErrorReset();
    2273          15 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    2274          15 :             char *pszRecoded = CPLRecode(poNewFieldDefn->GetNameRef(),
    2275             :                                          CPL_ENC_UTF8, m_osEncoding);
    2276          15 :             CPLPopErrorHandler();
    2277          15 :             osFieldName = pszRecoded;
    2278          15 :             CPLFree(pszRecoded);
    2279          15 :             if (CPLGetLastErrorType() != 0)
    2280             :             {
    2281           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2282             :                          "Failed to rename field name to '%s': "
    2283             :                          "cannot convert to %s",
    2284             :                          poNewFieldDefn->GetNameRef(), m_osEncoding.c_str());
    2285           1 :                 return OGRERR_FAILURE;
    2286             :             }
    2287             :         }
    2288             :         else
    2289             :         {
    2290           0 :             osFieldName = poNewFieldDefn->GetNameRef();
    2291             :         }
    2292             : 
    2293          14 :         strncpy(szFieldName, osFieldName, sizeof(szFieldName) - 1);
    2294          14 :         szFieldName[sizeof(szFieldName) - 1] = '\0';
    2295             :     }
    2296          15 :     if (nFlagsIn & ALTER_WIDTH_PRECISION_FLAG)
    2297             :     {
    2298          13 :         nWidth = poNewFieldDefn->GetWidth();
    2299          13 :         nPrecision = poNewFieldDefn->GetPrecision();
    2300             :     }
    2301             : 
    2302          15 :     if (DBFAlterFieldDefn(m_hDBF, iField, szFieldName, chNativeType, nWidth,
    2303          15 :                           nPrecision))
    2304             :     {
    2305          15 :         if (nFlagsIn & ALTER_TYPE_FLAG)
    2306          14 :             poFieldDefn->SetType(eType);
    2307          15 :         if (nFlagsIn & ALTER_NAME_FLAG)
    2308          14 :             poFieldDefn->SetName(poNewFieldDefn->GetNameRef());
    2309          15 :         if (nFlagsIn & ALTER_WIDTH_PRECISION_FLAG)
    2310             :         {
    2311          13 :             poFieldDefn->SetWidth(nWidth);
    2312          13 :             poFieldDefn->SetPrecision(nPrecision);
    2313             : 
    2314          13 :             TruncateDBF();
    2315             :         }
    2316          15 :         return OGRERR_NONE;
    2317             :     }
    2318             : 
    2319           0 :     return OGRERR_FAILURE;
    2320             : }
    2321             : 
    2322             : /************************************************************************/
    2323             : /*                         AlterGeomFieldDefn()                         */
    2324             : /************************************************************************/
    2325             : 
    2326           6 : OGRErr OGRShapeLayer::AlterGeomFieldDefn(
    2327             :     int iGeomField, const OGRGeomFieldDefn *poNewGeomFieldDefn, int nFlagsIn)
    2328             : {
    2329           6 :     if (!StartUpdate("AlterGeomFieldDefn"))
    2330           0 :         return OGRERR_FAILURE;
    2331             : 
    2332           6 :     if (iGeomField < 0 || iGeomField >= m_poFeatureDefn->GetGeomFieldCount())
    2333             :     {
    2334           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2335           1 :         return OGRERR_FAILURE;
    2336             :     }
    2337             : 
    2338           5 :     auto poFieldDefn = cpl::down_cast<OGRShapeGeomFieldDefn *>(
    2339           5 :         m_poFeatureDefn->GetGeomFieldDefn(iGeomField));
    2340          10 :     auto oTemporaryUnsealer(poFieldDefn->GetTemporaryUnsealer());
    2341             : 
    2342           5 :     if (nFlagsIn & ALTER_GEOM_FIELD_DEFN_NAME_FLAG)
    2343             :     {
    2344           5 :         if (strcmp(poNewGeomFieldDefn->GetNameRef(),
    2345           5 :                    poFieldDefn->GetNameRef()) != 0)
    2346             :         {
    2347           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2348             :                      "Altering the geometry field name is not supported for "
    2349             :                      "shapefiles");
    2350           0 :             return OGRERR_FAILURE;
    2351             :         }
    2352             :     }
    2353             : 
    2354           5 :     if (nFlagsIn & ALTER_GEOM_FIELD_DEFN_TYPE_FLAG)
    2355             :     {
    2356           5 :         if (poFieldDefn->GetType() != poNewGeomFieldDefn->GetType())
    2357             :         {
    2358           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    2359             :                      "Altering the geometry field type is not supported for "
    2360             :                      "shapefiles");
    2361           1 :             return OGRERR_FAILURE;
    2362             :         }
    2363             :     }
    2364             : 
    2365           4 :     if (nFlagsIn & ALTER_GEOM_FIELD_DEFN_SRS_COORD_EPOCH_FLAG)
    2366             :     {
    2367           4 :         const auto poNewSRSRef = poNewGeomFieldDefn->GetSpatialRef();
    2368           4 :         if (poNewSRSRef && poNewSRSRef->GetCoordinateEpoch() > 0)
    2369             :         {
    2370           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    2371             :                      "Setting a coordinate epoch is not supported for "
    2372             :                      "shapefiles");
    2373           1 :             return OGRERR_FAILURE;
    2374             :         }
    2375             :     }
    2376             : 
    2377           3 :     if (nFlagsIn & ALTER_GEOM_FIELD_DEFN_SRS_FLAG)
    2378             :     {
    2379           3 :         if (poFieldDefn->GetPrjFilename().empty())
    2380             :         {
    2381           6 :             poFieldDefn->SetPrjFilename(
    2382           4 :                 CPLResetExtensionSafe(m_osFullName.c_str(), "prj").c_str());
    2383             :         }
    2384             : 
    2385           3 :         const auto poNewSRSRef = poNewGeomFieldDefn->GetSpatialRef();
    2386           3 :         if (poNewSRSRef)
    2387             :         {
    2388           2 :             char *pszWKT = nullptr;
    2389           2 :             VSILFILE *fp = nullptr;
    2390           2 :             const char *const apszOptions[] = {"FORMAT=WKT1_ESRI", nullptr};
    2391           4 :             if (poNewSRSRef->exportToWkt(&pszWKT, apszOptions) == OGRERR_NONE &&
    2392           2 :                 (fp = VSIFOpenL(poFieldDefn->GetPrjFilename().c_str(), "wt")) !=
    2393             :                     nullptr)
    2394             :             {
    2395           2 :                 VSIFWriteL(pszWKT, strlen(pszWKT), 1, fp);
    2396           2 :                 VSIFCloseL(fp);
    2397             :             }
    2398             :             else
    2399             :             {
    2400           0 :                 CPLError(CE_Failure, CPLE_FileIO, "Cannot write %s",
    2401           0 :                          poFieldDefn->GetPrjFilename().c_str());
    2402           0 :                 CPLFree(pszWKT);
    2403           0 :                 return OGRERR_FAILURE;
    2404             :             }
    2405             : 
    2406           2 :             CPLFree(pszWKT);
    2407             : 
    2408           2 :             auto poNewSRS = poNewSRSRef->Clone();
    2409           2 :             poFieldDefn->SetSpatialRef(poNewSRS);
    2410           2 :             poNewSRS->Release();
    2411             :         }
    2412             :         else
    2413             :         {
    2414           1 :             poFieldDefn->SetSpatialRef(nullptr);
    2415             :             VSIStatBufL sStat;
    2416           2 :             if (VSIStatL(poFieldDefn->GetPrjFilename().c_str(), &sStat) == 0 &&
    2417           1 :                 VSIUnlink(poFieldDefn->GetPrjFilename().c_str()) != 0)
    2418             :             {
    2419           0 :                 CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s",
    2420           0 :                          poFieldDefn->GetPrjFilename().c_str());
    2421           0 :                 return OGRERR_FAILURE;
    2422             :             }
    2423             :         }
    2424           3 :         poFieldDefn->SetSRSSet();
    2425             :     }
    2426             : 
    2427           3 :     if (nFlagsIn & ALTER_GEOM_FIELD_DEFN_NAME_FLAG)
    2428           3 :         poFieldDefn->SetName(poNewGeomFieldDefn->GetNameRef());
    2429           3 :     if (nFlagsIn & ALTER_GEOM_FIELD_DEFN_NULLABLE_FLAG)
    2430           3 :         poFieldDefn->SetNullable(poNewGeomFieldDefn->IsNullable());
    2431             : 
    2432           3 :     return OGRERR_NONE;
    2433             : }
    2434             : 
    2435             : /************************************************************************/
    2436             : /*                           GetSpatialRef()                            */
    2437             : /************************************************************************/
    2438             : 
    2439       96908 : const OGRSpatialReference *OGRShapeGeomFieldDefn::GetSpatialRef() const
    2440             : 
    2441             : {
    2442       96908 :     if (m_bSRSSet)
    2443       95159 :         return poSRS;
    2444             : 
    2445        1749 :     m_bSRSSet = true;
    2446             : 
    2447             :     /* -------------------------------------------------------------------- */
    2448             :     /*      Is there an associated .prj file we can read?                   */
    2449             :     /* -------------------------------------------------------------------- */
    2450             :     std::string l_osPrjFile =
    2451        1749 :         CPLResetExtensionSafe(m_osFullName.c_str(), "prj");
    2452             : 
    2453        1749 :     char *apszOptions[] = {
    2454             :         const_cast<char *>("EMIT_ERROR_IF_CANNOT_OPEN_FILE=FALSE"), nullptr};
    2455        1749 :     char **papszLines = CSLLoad2(l_osPrjFile.c_str(), -1, -1, apszOptions);
    2456        1749 :     if (papszLines == nullptr)
    2457             :     {
    2458        1406 :         l_osPrjFile = CPLResetExtensionSafe(m_osFullName.c_str(), "PRJ");
    2459        1406 :         papszLines = CSLLoad2(l_osPrjFile.c_str(), -1, -1, apszOptions);
    2460             :     }
    2461             : 
    2462        1749 :     if (papszLines != nullptr)
    2463             :     {
    2464         918 :         m_osPrjFile = std::move(l_osPrjFile);
    2465             : 
    2466         918 :         auto poSRSNonConst = new OGRSpatialReference();
    2467         918 :         poSRSNonConst->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    2468             :         // Remove UTF-8 BOM if found
    2469             :         // http://lists.osgeo.org/pipermail/gdal-dev/2014-July/039527.html
    2470         918 :         if (static_cast<unsigned char>(papszLines[0][0]) == 0xEF &&
    2471           1 :             static_cast<unsigned char>(papszLines[0][1]) == 0xBB &&
    2472           1 :             static_cast<unsigned char>(papszLines[0][2]) == 0xBF)
    2473             :         {
    2474           1 :             memmove(papszLines[0], papszLines[0] + 3,
    2475           1 :                     strlen(papszLines[0] + 3) + 1);
    2476             :         }
    2477         918 :         if (STARTS_WITH_CI(papszLines[0], "GEOGCS["))
    2478             :         {
    2479             :             // Strip AXIS[] in GEOGCS to address use case of
    2480             :             // https://github.com/OSGeo/gdal/issues/8452
    2481         558 :             std::string osVal;
    2482         569 :             for (CSLConstList papszIter = papszLines; *papszIter; ++papszIter)
    2483         290 :                 osVal += *papszIter;
    2484         558 :             OGR_SRSNode oSRSNode;
    2485         279 :             const char *pszVal = osVal.c_str();
    2486         279 :             if (oSRSNode.importFromWkt(&pszVal) == OGRERR_NONE)
    2487             :             {
    2488         279 :                 oSRSNode.StripNodes("AXIS");
    2489         279 :                 char *pszWKT = nullptr;
    2490         279 :                 oSRSNode.exportToWkt(&pszWKT);
    2491         279 :                 if (pszWKT)
    2492             :                 {
    2493         279 :                     CSLDestroy(papszLines);
    2494             :                     papszLines =
    2495         279 :                         static_cast<char **>(CPLCalloc(2, sizeof(char *)));
    2496         279 :                     papszLines[0] = pszWKT;
    2497             :                 }
    2498             :             }
    2499             :         }
    2500         918 :         if (poSRSNonConst->importFromESRI(papszLines) != OGRERR_NONE)
    2501             :         {
    2502           1 :             delete poSRSNonConst;
    2503           1 :             poSRSNonConst = nullptr;
    2504             :         }
    2505         918 :         CSLDestroy(papszLines);
    2506             : 
    2507         918 :         if (poSRSNonConst)
    2508             :         {
    2509             :             double adfTOWGS84[7];
    2510         917 :             const char *pszSRSName = poSRSNonConst->GetName();
    2511         917 :             if (CPLTestBool(
    2512        1834 :                     CPLGetConfigOption("USE_OSR_FIND_MATCHES", "YES")) &&
    2513             :                 // Below works around bug fixed in PROJ per
    2514             :                 // https://github.com/OSGeo/PROJ/pull/4599
    2515         917 :                 !(pszSRSName && strstr(pszSRSName, "NTF (Paris)") != nullptr &&
    2516           0 :                   poSRSNonConst->GetTOWGS84(adfTOWGS84) == OGRERR_NONE))
    2517             :             {
    2518         917 :                 auto poSRSMatch = poSRSNonConst->FindBestMatch();
    2519         917 :                 if (poSRSMatch)
    2520             :                 {
    2521         906 :                     poSRSNonConst->Release();
    2522         906 :                     poSRSNonConst = poSRSMatch;
    2523         906 :                     poSRSNonConst->SetAxisMappingStrategy(
    2524             :                         OAMS_TRADITIONAL_GIS_ORDER);
    2525             :                 }
    2526             :             }
    2527             :             else
    2528             :             {
    2529           0 :                 poSRSNonConst->AutoIdentifyEPSG();
    2530             :             }
    2531         917 :             poSRS = poSRSNonConst;
    2532             :         }
    2533             :     }
    2534             : 
    2535        1749 :     return poSRS;
    2536             : }
    2537             : 
    2538             : /************************************************************************/
    2539             : /*                           ResetGeomType()                            */
    2540             : /*                                                                      */
    2541             : /*      Modify the geometry type for this file.  Used to convert to     */
    2542             : /*      a different geometry type when a layer was created with a       */
    2543             : /*      type of unknown, and we get to the first feature to             */
    2544             : /*      establish the type.                                             */
    2545             : /************************************************************************/
    2546             : 
    2547         668 : int OGRShapeLayer::ResetGeomType(int nNewGeomType)
    2548             : 
    2549             : {
    2550         668 :     if (m_nTotalShapeCount > 0)
    2551           0 :         return FALSE;
    2552             : 
    2553         668 :     if (m_hSHP->fpSHX == nullptr)
    2554             :     {
    2555           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    2556             :                  "OGRShapeLayer::ResetGeomType failed: SHX file is closed");
    2557           0 :         return FALSE;
    2558             :     }
    2559             : 
    2560             :     /* -------------------------------------------------------------------- */
    2561             :     /*      Update .shp header.                                             */
    2562             :     /* -------------------------------------------------------------------- */
    2563         668 :     int nStartPos = static_cast<int>(m_hSHP->sHooks.FTell(m_hSHP->fpSHP));
    2564             : 
    2565         668 :     char abyHeader[100] = {};
    2566        1336 :     if (m_hSHP->sHooks.FSeek(m_hSHP->fpSHP, 0, SEEK_SET) != 0 ||
    2567         668 :         m_hSHP->sHooks.FRead(abyHeader, 100, 1, m_hSHP->fpSHP) != 1)
    2568           0 :         return FALSE;
    2569             : 
    2570         668 :     *(reinterpret_cast<GInt32 *>(abyHeader + 32)) = CPL_LSBWORD32(nNewGeomType);
    2571             : 
    2572        1336 :     if (m_hSHP->sHooks.FSeek(m_hSHP->fpSHP, 0, SEEK_SET) != 0 ||
    2573         668 :         m_hSHP->sHooks.FWrite(abyHeader, 100, 1, m_hSHP->fpSHP) != 1)
    2574           0 :         return FALSE;
    2575             : 
    2576         668 :     if (m_hSHP->sHooks.FSeek(m_hSHP->fpSHP, nStartPos, SEEK_SET) != 0)
    2577           0 :         return FALSE;
    2578             : 
    2579             :     /* -------------------------------------------------------------------- */
    2580             :     /*      Update .shx header.                                             */
    2581             :     /* -------------------------------------------------------------------- */
    2582         668 :     nStartPos = static_cast<int>(m_hSHP->sHooks.FTell(m_hSHP->fpSHX));
    2583             : 
    2584        1336 :     if (m_hSHP->sHooks.FSeek(m_hSHP->fpSHX, 0, SEEK_SET) != 0 ||
    2585         668 :         m_hSHP->sHooks.FRead(abyHeader, 100, 1, m_hSHP->fpSHX) != 1)
    2586           0 :         return FALSE;
    2587             : 
    2588         668 :     *(reinterpret_cast<GInt32 *>(abyHeader + 32)) = CPL_LSBWORD32(nNewGeomType);
    2589             : 
    2590        1336 :     if (m_hSHP->sHooks.FSeek(m_hSHP->fpSHX, 0, SEEK_SET) != 0 ||
    2591         668 :         m_hSHP->sHooks.FWrite(abyHeader, 100, 1, m_hSHP->fpSHX) != 1)
    2592           0 :         return FALSE;
    2593             : 
    2594         668 :     if (m_hSHP->sHooks.FSeek(m_hSHP->fpSHX, nStartPos, SEEK_SET) != 0)
    2595           0 :         return FALSE;
    2596             : 
    2597             :     /* -------------------------------------------------------------------- */
    2598             :     /*      Update other information.                                       */
    2599             :     /* -------------------------------------------------------------------- */
    2600         668 :     m_hSHP->nShapeType = nNewGeomType;
    2601             : 
    2602         668 :     return TRUE;
    2603             : }
    2604             : 
    2605             : /************************************************************************/
    2606             : /*                             SyncToDisk()                             */
    2607             : /************************************************************************/
    2608             : 
    2609        7541 : OGRErr OGRShapeLayer::SyncToDisk()
    2610             : 
    2611             : {
    2612        7541 :     if (!TouchLayer())
    2613           0 :         return OGRERR_FAILURE;
    2614             : 
    2615        7541 :     if (m_bHeaderDirty)
    2616             :     {
    2617        1763 :         if (m_hSHP != nullptr)
    2618        1626 :             SHPWriteHeader(m_hSHP);
    2619             : 
    2620        1763 :         if (m_hDBF != nullptr)
    2621        1761 :             DBFUpdateHeader(m_hDBF);
    2622             : 
    2623        1763 :         m_bHeaderDirty = false;
    2624             :     }
    2625             : 
    2626        7541 :     if (m_hSHP != nullptr)
    2627             :     {
    2628        6656 :         m_hSHP->sHooks.FFlush(m_hSHP->fpSHP);
    2629        6656 :         if (m_hSHP->fpSHX != nullptr)
    2630        3205 :             m_hSHP->sHooks.FFlush(m_hSHP->fpSHX);
    2631             :     }
    2632             : 
    2633        7541 :     if (m_hDBF != nullptr)
    2634             :     {
    2635        7482 :         m_hDBF->sHooks.FFlush(m_hDBF->fp);
    2636             :     }
    2637             : 
    2638        7541 :     if (m_eNeedRepack == YES && m_bAutoRepack)
    2639          21 :         Repack();
    2640             : 
    2641        7541 :     return OGRERR_NONE;
    2642             : }
    2643             : 
    2644             : /************************************************************************/
    2645             : /*                          DropSpatialIndex()                          */
    2646             : /************************************************************************/
    2647             : 
    2648           9 : OGRErr OGRShapeLayer::DropSpatialIndex()
    2649             : 
    2650             : {
    2651           9 :     if (!StartUpdate("DropSpatialIndex"))
    2652           0 :         return OGRERR_FAILURE;
    2653             : 
    2654           9 :     if (!CheckForQIX() && !CheckForSBN())
    2655             :     {
    2656           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2657             :                  "Layer %s has no spatial index, DROP SPATIAL INDEX failed.",
    2658           1 :                  m_poFeatureDefn->GetName());
    2659           1 :         return OGRERR_FAILURE;
    2660             :     }
    2661             : 
    2662           8 :     const bool bHadQIX = m_hQIX != nullptr;
    2663             : 
    2664           8 :     SHPCloseDiskTree(m_hQIX);
    2665           8 :     m_hQIX = nullptr;
    2666           8 :     m_bCheckedForQIX = false;
    2667             : 
    2668           8 :     SBNCloseDiskTree(m_hSBN);
    2669           8 :     m_hSBN = nullptr;
    2670           8 :     m_bCheckedForSBN = false;
    2671             : 
    2672           8 :     if (bHadQIX)
    2673             :     {
    2674             :         const std::string osQIXFilename =
    2675           7 :             CPLResetExtensionSafe(m_osFullName.c_str(), "qix");
    2676           7 :         CPLDebug("SHAPE", "Unlinking index file %s", osQIXFilename.c_str());
    2677             : 
    2678           7 :         if (VSIUnlink(osQIXFilename.c_str()) != 0)
    2679             :         {
    2680           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2681             :                      "Failed to delete file %s.\n%s", osQIXFilename.c_str(),
    2682           0 :                      VSIStrerror(errno));
    2683           0 :             return OGRERR_FAILURE;
    2684             :         }
    2685             :     }
    2686             : 
    2687           8 :     if (!m_bSbnSbxDeleted)
    2688             :     {
    2689           7 :         const char papszExt[2][4] = {"sbn", "sbx"};
    2690          21 :         for (int i = 0; i < 2; i++)
    2691             :         {
    2692             :             const std::string osIndexFilename =
    2693          28 :                 CPLResetExtensionSafe(m_osFullName.c_str(), papszExt[i]);
    2694          14 :             CPLDebug("SHAPE", "Trying to unlink index file %s",
    2695             :                      osIndexFilename.c_str());
    2696             : 
    2697          14 :             if (VSIUnlink(osIndexFilename.c_str()) != 0)
    2698             :             {
    2699           6 :                 CPLDebug("SHAPE", "Failed to delete file %s.\n%s",
    2700           6 :                          osIndexFilename.c_str(), VSIStrerror(errno));
    2701             :             }
    2702             :         }
    2703             :     }
    2704           8 :     m_bSbnSbxDeleted = true;
    2705             : 
    2706           8 :     ClearSpatialFIDs();
    2707             : 
    2708           8 :     return OGRERR_NONE;
    2709             : }
    2710             : 
    2711             : /************************************************************************/
    2712             : /*                         CreateSpatialIndex()                         */
    2713             : /************************************************************************/
    2714             : 
    2715          17 : OGRErr OGRShapeLayer::CreateSpatialIndex(int nMaxDepth)
    2716             : 
    2717             : {
    2718          17 :     if (!StartUpdate("CreateSpatialIndex"))
    2719           0 :         return OGRERR_FAILURE;
    2720             : 
    2721             :     /* -------------------------------------------------------------------- */
    2722             :     /*      If we have an existing spatial index, blow it away first.       */
    2723             :     /* -------------------------------------------------------------------- */
    2724          17 :     if (CheckForQIX())
    2725           1 :         DropSpatialIndex();
    2726             : 
    2727          17 :     m_bCheckedForQIX = false;
    2728             : 
    2729             :     /* -------------------------------------------------------------------- */
    2730             :     /*      Build a quadtree structure for this file.                       */
    2731             :     /* -------------------------------------------------------------------- */
    2732          17 :     OGRShapeLayer::SyncToDisk();
    2733          17 :     SHPTree *psTree = SHPCreateTree(m_hSHP, 2, nMaxDepth, nullptr, nullptr);
    2734             : 
    2735          17 :     if (nullptr == psTree)
    2736             :     {
    2737             :         // TODO(mloskot): Is it better to return OGRERR_NOT_ENOUGH_MEMORY?
    2738           0 :         CPLDebug("SHAPE",
    2739             :                  "Index creation failure. Likely, memory allocation error.");
    2740             : 
    2741           0 :         return OGRERR_FAILURE;
    2742             :     }
    2743             : 
    2744             :     /* -------------------------------------------------------------------- */
    2745             :     /*      Trim unused nodes from the tree.                                */
    2746             :     /* -------------------------------------------------------------------- */
    2747          17 :     SHPTreeTrimExtraNodes(psTree);
    2748             : 
    2749             :     /* -------------------------------------------------------------------- */
    2750             :     /*      Dump tree to .qix file.                                         */
    2751             :     /* -------------------------------------------------------------------- */
    2752             :     char *pszQIXFilename =
    2753          17 :         CPLStrdup(CPLResetExtensionSafe(m_osFullName.c_str(), "qix").c_str());
    2754             : 
    2755          17 :     CPLDebug("SHAPE", "Creating index file %s", pszQIXFilename);
    2756             : 
    2757          17 :     SHPWriteTree(psTree, pszQIXFilename);
    2758          17 :     CPLFree(pszQIXFilename);
    2759             : 
    2760             :     /* -------------------------------------------------------------------- */
    2761             :     /*      cleanup                                                         */
    2762             :     /* -------------------------------------------------------------------- */
    2763          17 :     SHPDestroyTree(psTree);
    2764             : 
    2765          17 :     CPL_IGNORE_RET_VAL(CheckForQIX());
    2766             : 
    2767          17 :     return OGRERR_NONE;
    2768             : }
    2769             : 
    2770             : /************************************************************************/
    2771             : /*                       CheckFileDeletion()                            */
    2772             : /************************************************************************/
    2773             : 
    2774          73 : static void CheckFileDeletion(const CPLString &osFilename)
    2775             : {
    2776             :     // On Windows, sometimes the file is still triansiently reported
    2777             :     // as existing although being deleted, which makes QGIS things that
    2778             :     // an issue arose. The following helps to reduce that risk.
    2779             :     VSIStatBufL sStat;
    2780          73 :     if (VSIStatL(osFilename, &sStat) == 0 && VSIStatL(osFilename, &sStat) == 0)
    2781             :     {
    2782           0 :         CPLDebug("Shape",
    2783             :                  "File %s is still reported as existing whereas "
    2784             :                  "it should have been deleted",
    2785             :                  osFilename.c_str());
    2786             :     }
    2787          73 : }
    2788             : 
    2789             : /************************************************************************/
    2790             : /*                         ForceDeleteFile()                            */
    2791             : /************************************************************************/
    2792             : 
    2793           6 : static void ForceDeleteFile(const CPLString &osFilename)
    2794             : {
    2795           6 :     if (VSIUnlink(osFilename) != 0)
    2796             :     {
    2797             :         // In case of failure retry with a small delay (Windows specific)
    2798           0 :         CPLSleep(0.1);
    2799           0 :         if (VSIUnlink(osFilename) != 0)
    2800             :         {
    2801           0 :             CPLDebug("Shape", "Cannot delete %s : %s", osFilename.c_str(),
    2802           0 :                      VSIStrerror(errno));
    2803             :         }
    2804             :     }
    2805           6 :     CheckFileDeletion(osFilename);
    2806           6 : }
    2807             : 
    2808             : /************************************************************************/
    2809             : /*                               Repack()                               */
    2810             : /*                                                                      */
    2811             : /*      Repack the shape and dbf file, dropping deleted records.        */
    2812             : /*      FIDs may change.                                                */
    2813             : /************************************************************************/
    2814             : 
    2815          40 : OGRErr OGRShapeLayer::Repack()
    2816             : 
    2817             : {
    2818          40 :     if (m_eNeedRepack == NO)
    2819             :     {
    2820           1 :         CPLDebug("Shape", "REPACK: nothing to do. Was done previously");
    2821           1 :         return OGRERR_NONE;
    2822             :     }
    2823             : 
    2824          39 :     if (!StartUpdate("Repack"))
    2825           1 :         return OGRERR_FAILURE;
    2826             : 
    2827             :     /* -------------------------------------------------------------------- */
    2828             :     /*      Build a list of records to be dropped.                          */
    2829             :     /* -------------------------------------------------------------------- */
    2830          76 :     std::vector<int> anRecordsToDelete;
    2831          38 :     OGRErr eErr = OGRERR_NONE;
    2832             : 
    2833          38 :     CPLDebug("Shape", "REPACK: Checking if features have been deleted");
    2834             : 
    2835          38 :     if (m_hDBF != nullptr)
    2836             :     {
    2837             :         try
    2838             :         {
    2839         510 :             for (int iShape = 0; iShape < m_nTotalShapeCount; iShape++)
    2840             :             {
    2841         475 :                 if (DBFIsRecordDeleted(m_hDBF, iShape))
    2842             :                 {
    2843         212 :                     anRecordsToDelete.push_back(iShape);
    2844             :                 }
    2845         950 :                 if (VSIFEofL(VSI_SHP_GetVSIL(m_hDBF->fp)) ||
    2846         475 :                     VSIFErrorL(VSI_SHP_GetVSIL(m_hDBF->fp)))
    2847             :                 {
    2848           0 :                     return OGRERR_FAILURE;  // I/O error.
    2849             :                 }
    2850             :             }
    2851             :         }
    2852           0 :         catch (const std::bad_alloc &)
    2853             :         {
    2854           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory in Repack()");
    2855           0 :             return OGRERR_FAILURE;
    2856             :         }
    2857             :     }
    2858             : 
    2859             :     /* -------------------------------------------------------------------- */
    2860             :     /*      If there are no records marked for deletion, we take no         */
    2861             :     /*      action.                                                         */
    2862             :     /* -------------------------------------------------------------------- */
    2863          38 :     if (anRecordsToDelete.empty() && !m_bSHPNeedsRepack)
    2864             :     {
    2865           8 :         CPLDebug("Shape", "REPACK: nothing to do");
    2866           8 :         return OGRERR_NONE;
    2867             :     }
    2868             : 
    2869             :     /* -------------------------------------------------------------------- */
    2870             :     /*      Find existing filenames with exact case (see #3293).            */
    2871             :     /* -------------------------------------------------------------------- */
    2872          60 :     const CPLString osDirname(CPLGetPathSafe(m_osFullName.c_str()));
    2873          60 :     const CPLString osBasename(CPLGetBasenameSafe(m_osFullName.c_str()));
    2874             : 
    2875          60 :     CPLString osDBFName;
    2876          60 :     CPLString osSHPName;
    2877          60 :     CPLString osSHXName;
    2878          60 :     CPLString osCPGName;
    2879          30 :     char **papszCandidates = VSIReadDir(osDirname);
    2880          30 :     int i = 0;
    2881         171 :     while (papszCandidates != nullptr && papszCandidates[i] != nullptr)
    2882             :     {
    2883             :         const CPLString osCandidateBasename =
    2884         282 :             CPLGetBasenameSafe(papszCandidates[i]);
    2885             :         const CPLString osCandidateExtension =
    2886         141 :             CPLGetExtensionSafe(papszCandidates[i]);
    2887             : #ifdef _WIN32
    2888             :         // On Windows, as filenames are case insensitive, a shapefile layer can
    2889             :         // be made of foo.shp and FOO.DBF, so use case insensitive comparison.
    2890             :         if (EQUAL(osCandidateBasename, osBasename))
    2891             : #else
    2892         141 :         if (osCandidateBasename.compare(osBasename) == 0)
    2893             : #endif
    2894             :         {
    2895          88 :             if (EQUAL(osCandidateExtension, "dbf"))
    2896             :                 osDBFName =
    2897          30 :                     CPLFormFilenameSafe(osDirname, papszCandidates[i], nullptr);
    2898          58 :             else if (EQUAL(osCandidateExtension, "shp"))
    2899             :                 osSHPName =
    2900          23 :                     CPLFormFilenameSafe(osDirname, papszCandidates[i], nullptr);
    2901          35 :             else if (EQUAL(osCandidateExtension, "shx"))
    2902             :                 osSHXName =
    2903          23 :                     CPLFormFilenameSafe(osDirname, papszCandidates[i], nullptr);
    2904          12 :             else if (EQUAL(osCandidateExtension, "cpg"))
    2905             :                 osCPGName =
    2906           3 :                     CPLFormFilenameSafe(osDirname, papszCandidates[i], nullptr);
    2907             :         }
    2908             : 
    2909         141 :         i++;
    2910             :     }
    2911          30 :     CSLDestroy(papszCandidates);
    2912          30 :     papszCandidates = nullptr;
    2913             : 
    2914          30 :     if (m_hDBF != nullptr && osDBFName.empty())
    2915             :     {
    2916           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2917             :                  "Cannot find the filename of the DBF file, but we managed to "
    2918             :                  "open it before !");
    2919             :         // Should not happen, really.
    2920           0 :         return OGRERR_FAILURE;
    2921             :     }
    2922             : 
    2923          30 :     if (m_hSHP != nullptr && osSHPName.empty())
    2924             :     {
    2925           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2926             :                  "Cannot find the filename of the SHP file, but we managed to "
    2927             :                  "open it before !");
    2928             :         // Should not happen, really.
    2929           0 :         return OGRERR_FAILURE;
    2930             :     }
    2931             : 
    2932          30 :     if (m_hSHP != nullptr && osSHXName.empty())
    2933             :     {
    2934           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2935             :                  "Cannot find the filename of the SHX file, but we managed to "
    2936             :                  "open it before !");
    2937             :         // Should not happen, really.
    2938           0 :         return OGRERR_FAILURE;
    2939             :     }
    2940             : 
    2941             :     /* -------------------------------------------------------------------- */
    2942             :     /*      Cleanup any existing spatial index.  It will become             */
    2943             :     /*      meaningless when the fids change.                               */
    2944             :     /* -------------------------------------------------------------------- */
    2945          30 :     if (CheckForQIX() || CheckForSBN())
    2946           0 :         DropSpatialIndex();
    2947             : 
    2948             :     /* -------------------------------------------------------------------- */
    2949             :     /*      Create a new dbf file, matching the old.                        */
    2950             :     /* -------------------------------------------------------------------- */
    2951          30 :     bool bMustReopenDBF = false;
    2952          60 :     CPLString oTempFileDBF;
    2953             :     const int nNewRecords =
    2954          30 :         m_nTotalShapeCount - static_cast<int>(anRecordsToDelete.size());
    2955             : 
    2956          30 :     if (m_hDBF != nullptr && !anRecordsToDelete.empty())
    2957             :     {
    2958          24 :         CPLDebug("Shape", "REPACK: repacking .dbf");
    2959          24 :         bMustReopenDBF = true;
    2960             : 
    2961          24 :         oTempFileDBF = CPLFormFilenameSafe(osDirname, osBasename, nullptr);
    2962          24 :         oTempFileDBF += "_packed.dbf";
    2963             : 
    2964          24 :         DBFHandle hNewDBF = DBFCloneEmpty(m_hDBF, oTempFileDBF);
    2965          24 :         if (hNewDBF == nullptr)
    2966             :         {
    2967           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    2968             :                      "Failed to create temp file %s.", oTempFileDBF.c_str());
    2969           0 :             return OGRERR_FAILURE;
    2970             :         }
    2971             : 
    2972             :         // Delete temporary .cpg file if existing.
    2973          24 :         if (!osCPGName.empty())
    2974             :         {
    2975             :             CPLString oCPGTempFile =
    2976           6 :                 CPLFormFilenameSafe(osDirname, osBasename, nullptr);
    2977           3 :             oCPGTempFile += "_packed.cpg";
    2978           3 :             ForceDeleteFile(oCPGTempFile);
    2979             :         }
    2980             : 
    2981             :         /* --------------------------------------------------------------------
    2982             :          */
    2983             :         /*      Copy over all records that are not deleted. */
    2984             :         /* --------------------------------------------------------------------
    2985             :          */
    2986          24 :         int iDestShape = 0;
    2987          24 :         size_t iNextDeletedShape = 0;
    2988             : 
    2989         400 :         for (int iShape = 0; iShape < m_nTotalShapeCount && eErr == OGRERR_NONE;
    2990             :              iShape++)
    2991             :         {
    2992         644 :             if (iNextDeletedShape < anRecordsToDelete.size() &&
    2993         268 :                 anRecordsToDelete[iNextDeletedShape] == iShape)
    2994             :             {
    2995         212 :                 iNextDeletedShape++;
    2996             :             }
    2997             :             else
    2998             :             {
    2999         164 :                 void *pTuple = const_cast<char *>(DBFReadTuple(m_hDBF, iShape));
    3000         328 :                 if (pTuple == nullptr ||
    3001         164 :                     !DBFWriteTuple(hNewDBF, iDestShape++, pTuple))
    3002             :                 {
    3003           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    3004             :                              "Error writing record %d in .dbf", iShape);
    3005           0 :                     eErr = OGRERR_FAILURE;
    3006             :                 }
    3007             :             }
    3008             :         }
    3009             : 
    3010          24 :         DBFClose(hNewDBF);
    3011             : 
    3012          24 :         if (eErr != OGRERR_NONE)
    3013             :         {
    3014           0 :             VSIUnlink(oTempFileDBF);
    3015           0 :             return eErr;
    3016             :         }
    3017             :     }
    3018             : 
    3019             :     /* -------------------------------------------------------------------- */
    3020             :     /*      Now create a shapefile matching the old one.                    */
    3021             :     /* -------------------------------------------------------------------- */
    3022          30 :     bool bMustReopenSHP = m_hSHP != nullptr;
    3023          60 :     CPLString oTempFileSHP;
    3024          60 :     CPLString oTempFileSHX;
    3025             : 
    3026             :     SHPInfo sSHPInfo;
    3027          30 :     memset(&sSHPInfo, 0, sizeof(sSHPInfo));
    3028          30 :     unsigned int *panRecOffsetNew = nullptr;
    3029          30 :     unsigned int *panRecSizeNew = nullptr;
    3030             : 
    3031             :     // On Windows, use the pack-in-place approach, ie copy the content of
    3032             :     // the _packed files on top of the existing opened files. This avoids
    3033             :     // many issues with files being locked, at the expense of more I/O
    3034             :     const bool bPackInPlace =
    3035          30 :         CPLTestBool(CPLGetConfigOption("OGR_SHAPE_PACK_IN_PLACE",
    3036             : #ifdef _WIN32
    3037             :                                        "YES"
    3038             : #else
    3039             :                                        "NO"
    3040             : #endif
    3041             :                                        ));
    3042             : 
    3043          30 :     if (m_hSHP != nullptr)
    3044             :     {
    3045          23 :         CPLDebug("Shape", "REPACK: repacking .shp + .shx");
    3046             : 
    3047          23 :         oTempFileSHP = CPLFormFilenameSafe(osDirname, osBasename, nullptr);
    3048          23 :         oTempFileSHP += "_packed.shp";
    3049          23 :         oTempFileSHX = CPLFormFilenameSafe(osDirname, osBasename, nullptr);
    3050          23 :         oTempFileSHX += "_packed.shx";
    3051             : 
    3052          23 :         SHPHandle hNewSHP = SHPCreate(oTempFileSHP, m_hSHP->nShapeType);
    3053          23 :         if (hNewSHP == nullptr)
    3054             :         {
    3055           0 :             if (!oTempFileDBF.empty())
    3056           0 :                 VSIUnlink(oTempFileDBF);
    3057           0 :             return OGRERR_FAILURE;
    3058             :         }
    3059             : 
    3060             :         /* --------------------------------------------------------------------
    3061             :          */
    3062             :         /*      Copy over all records that are not deleted. */
    3063             :         /* --------------------------------------------------------------------
    3064             :          */
    3065          23 :         size_t iNextDeletedShape = 0;
    3066             : 
    3067         191 :         for (int iShape = 0; iShape < m_nTotalShapeCount && eErr == OGRERR_NONE;
    3068             :              iShape++)
    3069             :         {
    3070         241 :             if (iNextDeletedShape < anRecordsToDelete.size() &&
    3071          73 :                 anRecordsToDelete[iNextDeletedShape] == iShape)
    3072             :             {
    3073          17 :                 iNextDeletedShape++;
    3074             :             }
    3075             :             else
    3076             :             {
    3077         151 :                 SHPObject *hObject = SHPReadObject(m_hSHP, iShape);
    3078         302 :                 if (hObject == nullptr ||
    3079         151 :                     SHPWriteObject(hNewSHP, -1, hObject) == -1)
    3080             :                 {
    3081           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    3082             :                              "Error writing record %d in .shp", iShape);
    3083           0 :                     eErr = OGRERR_FAILURE;
    3084             :                 }
    3085             : 
    3086         151 :                 if (hObject)
    3087         151 :                     SHPDestroyObject(hObject);
    3088             :             }
    3089             :         }
    3090             : 
    3091          23 :         if (bPackInPlace)
    3092             :         {
    3093             :             // Backup information of the updated shape context so as to
    3094             :             // restore it later in the current shape context
    3095           1 :             memcpy(&sSHPInfo, hNewSHP, sizeof(sSHPInfo));
    3096             : 
    3097             :             // Use malloc like shapelib does
    3098             :             panRecOffsetNew = reinterpret_cast<unsigned int *>(
    3099           1 :                 malloc(sizeof(unsigned int) * hNewSHP->nMaxRecords));
    3100             :             panRecSizeNew = reinterpret_cast<unsigned int *>(
    3101           1 :                 malloc(sizeof(unsigned int) * hNewSHP->nMaxRecords));
    3102           1 :             if (panRecOffsetNew == nullptr || panRecSizeNew == nullptr)
    3103             :             {
    3104           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    3105             :                          "Cannot allocate panRecOffsetNew/panRecSizeNew");
    3106           0 :                 eErr = OGRERR_FAILURE;
    3107             :             }
    3108             :             else
    3109             :             {
    3110           1 :                 memcpy(panRecOffsetNew, hNewSHP->panRecOffset,
    3111           1 :                        sizeof(unsigned int) * hNewSHP->nRecords);
    3112           1 :                 memcpy(panRecSizeNew, hNewSHP->panRecSize,
    3113           1 :                        sizeof(unsigned int) * hNewSHP->nRecords);
    3114             :             }
    3115             :         }
    3116             : 
    3117          23 :         SHPClose(hNewSHP);
    3118             : 
    3119          23 :         if (eErr != OGRERR_NONE)
    3120             :         {
    3121           0 :             VSIUnlink(oTempFileSHP);
    3122           0 :             VSIUnlink(oTempFileSHX);
    3123           0 :             if (!oTempFileDBF.empty())
    3124           0 :                 VSIUnlink(oTempFileDBF);
    3125           0 :             free(panRecOffsetNew);
    3126           0 :             free(panRecSizeNew);
    3127           0 :             return eErr;
    3128             :         }
    3129             :     }
    3130             : 
    3131             :     // We could also use pack in place for Unix but this involves extra I/O
    3132             :     // w.r.t to the delete and rename approach
    3133             : 
    3134          30 :     if (bPackInPlace)
    3135             :     {
    3136           1 :         if (m_hDBF != nullptr && !oTempFileDBF.empty())
    3137             :         {
    3138           1 :             if (!OGRShapeDataSource::CopyInPlace(VSI_SHP_GetVSIL(m_hDBF->fp),
    3139             :                                                  oTempFileDBF))
    3140             :             {
    3141           0 :                 CPLError(
    3142             :                     CE_Failure, CPLE_FileIO,
    3143             :                     "An error occurred while copying the content of %s on top "
    3144             :                     "of %s. "
    3145             :                     "The non corrupted version is in the _packed.dbf, "
    3146             :                     "_packed.shp and _packed.shx files that you should rename "
    3147             :                     "on top of the main ones.",
    3148           0 :                     oTempFileDBF.c_str(), VSI_SHP_GetFilename(m_hDBF->fp));
    3149           0 :                 free(panRecOffsetNew);
    3150           0 :                 free(panRecSizeNew);
    3151             : 
    3152           0 :                 DBFClose(m_hDBF);
    3153           0 :                 m_hDBF = nullptr;
    3154           0 :                 if (m_hSHP != nullptr)
    3155             :                 {
    3156           0 :                     SHPClose(m_hSHP);
    3157           0 :                     m_hSHP = nullptr;
    3158             :                 }
    3159             : 
    3160           0 :                 return OGRERR_FAILURE;
    3161             :             }
    3162             : 
    3163             :             // Refresh current handle
    3164           1 :             m_hDBF->nRecords = nNewRecords;
    3165             :         }
    3166             : 
    3167           1 :         if (m_hSHP != nullptr && !oTempFileSHP.empty())
    3168             :         {
    3169           1 :             if (!OGRShapeDataSource::CopyInPlace(VSI_SHP_GetVSIL(m_hSHP->fpSHP),
    3170             :                                                  oTempFileSHP))
    3171             :             {
    3172           0 :                 CPLError(
    3173             :                     CE_Failure, CPLE_FileIO,
    3174             :                     "An error occurred while copying the content of %s on top "
    3175             :                     "of %s. "
    3176             :                     "The non corrupted version is in the _packed.dbf, "
    3177             :                     "_packed.shp and _packed.shx files that you should rename "
    3178             :                     "on top of the main ones.",
    3179           0 :                     oTempFileSHP.c_str(), VSI_SHP_GetFilename(m_hSHP->fpSHP));
    3180           0 :                 free(panRecOffsetNew);
    3181           0 :                 free(panRecSizeNew);
    3182             : 
    3183           0 :                 if (m_hDBF != nullptr)
    3184             :                 {
    3185           0 :                     DBFClose(m_hDBF);
    3186           0 :                     m_hDBF = nullptr;
    3187             :                 }
    3188           0 :                 SHPClose(m_hSHP);
    3189           0 :                 m_hSHP = nullptr;
    3190             : 
    3191           0 :                 return OGRERR_FAILURE;
    3192             :             }
    3193           1 :             if (!OGRShapeDataSource::CopyInPlace(VSI_SHP_GetVSIL(m_hSHP->fpSHX),
    3194             :                                                  oTempFileSHX))
    3195             :             {
    3196           0 :                 CPLError(
    3197             :                     CE_Failure, CPLE_FileIO,
    3198             :                     "An error occurred while copying the content of %s on top "
    3199             :                     "of %s. "
    3200             :                     "The non corrupted version is in the _packed.dbf, "
    3201             :                     "_packed.shp and _packed.shx files that you should rename "
    3202             :                     "on top of the main ones.",
    3203           0 :                     oTempFileSHX.c_str(), VSI_SHP_GetFilename(m_hSHP->fpSHX));
    3204           0 :                 free(panRecOffsetNew);
    3205           0 :                 free(panRecSizeNew);
    3206             : 
    3207           0 :                 if (m_hDBF != nullptr)
    3208             :                 {
    3209           0 :                     DBFClose(m_hDBF);
    3210           0 :                     m_hDBF = nullptr;
    3211             :                 }
    3212           0 :                 SHPClose(m_hSHP);
    3213           0 :                 m_hSHP = nullptr;
    3214             : 
    3215           0 :                 return OGRERR_FAILURE;
    3216             :             }
    3217             : 
    3218             :             // Refresh current handle
    3219           1 :             m_hSHP->nRecords = sSHPInfo.nRecords;
    3220           1 :             m_hSHP->nMaxRecords = sSHPInfo.nMaxRecords;
    3221           1 :             m_hSHP->nFileSize = sSHPInfo.nFileSize;
    3222             :             CPLAssert(sizeof(sSHPInfo.adBoundsMin) == 4 * sizeof(double));
    3223           1 :             memcpy(m_hSHP->adBoundsMin, sSHPInfo.adBoundsMin,
    3224             :                    sizeof(sSHPInfo.adBoundsMin));
    3225           1 :             memcpy(m_hSHP->adBoundsMax, sSHPInfo.adBoundsMax,
    3226             :                    sizeof(sSHPInfo.adBoundsMax));
    3227           1 :             free(m_hSHP->panRecOffset);
    3228           1 :             free(m_hSHP->panRecSize);
    3229           1 :             m_hSHP->panRecOffset = panRecOffsetNew;
    3230           1 :             m_hSHP->panRecSize = panRecSizeNew;
    3231             :         }
    3232             :         else
    3233             :         {
    3234             :             // The free() are not really necessary but CSA doesn't realize it
    3235           0 :             free(panRecOffsetNew);
    3236           0 :             free(panRecSizeNew);
    3237             :         }
    3238             : 
    3239             :         // Now that everything is successful, we can delete the temp files
    3240           1 :         if (!oTempFileDBF.empty())
    3241             :         {
    3242           1 :             ForceDeleteFile(oTempFileDBF);
    3243             :         }
    3244           1 :         if (!oTempFileSHP.empty())
    3245             :         {
    3246           1 :             ForceDeleteFile(oTempFileSHP);
    3247           1 :             ForceDeleteFile(oTempFileSHX);
    3248             :         }
    3249             :     }
    3250             :     else
    3251             :     {
    3252             :         /* --------------------------------------------------------------------
    3253             :          */
    3254             :         /*      Cleanup the old .dbf, .shp, .shx and rename the new ones. */
    3255             :         /* --------------------------------------------------------------------
    3256             :          */
    3257          29 :         if (!oTempFileDBF.empty())
    3258             :         {
    3259          23 :             DBFClose(m_hDBF);
    3260          23 :             m_hDBF = nullptr;
    3261             : 
    3262          23 :             if (VSIUnlink(osDBFName) != 0)
    3263             :             {
    3264           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3265             :                          "Failed to delete old DBF file: %s",
    3266           0 :                          VSIStrerror(errno));
    3267             : 
    3268           0 :                 m_hDBF =
    3269           0 :                     m_poDS->DS_DBFOpen(osDBFName, m_bUpdateAccess ? "r+" : "r");
    3270             : 
    3271           0 :                 VSIUnlink(oTempFileDBF);
    3272             : 
    3273           0 :                 return OGRERR_FAILURE;
    3274             :             }
    3275             : 
    3276          23 :             if (VSIRename(oTempFileDBF, osDBFName) != 0)
    3277             :             {
    3278           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3279           0 :                          "Can not rename new DBF file: %s", VSIStrerror(errno));
    3280           0 :                 return OGRERR_FAILURE;
    3281             :             }
    3282             : 
    3283          23 :             CheckFileDeletion(oTempFileDBF);
    3284             :         }
    3285             : 
    3286          29 :         if (!oTempFileSHP.empty())
    3287             :         {
    3288          22 :             SHPClose(m_hSHP);
    3289          22 :             m_hSHP = nullptr;
    3290             : 
    3291          22 :             if (VSIUnlink(osSHPName) != 0)
    3292             :             {
    3293           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3294           0 :                          "Can not delete old SHP file: %s", VSIStrerror(errno));
    3295           0 :                 return OGRERR_FAILURE;
    3296             :             }
    3297             : 
    3298          22 :             if (VSIUnlink(osSHXName) != 0)
    3299             :             {
    3300           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3301           0 :                          "Can not delete old SHX file: %s", VSIStrerror(errno));
    3302           0 :                 return OGRERR_FAILURE;
    3303             :             }
    3304             : 
    3305          22 :             if (VSIRename(oTempFileSHP, osSHPName) != 0)
    3306             :             {
    3307           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3308           0 :                          "Can not rename new SHP file: %s", VSIStrerror(errno));
    3309           0 :                 return OGRERR_FAILURE;
    3310             :             }
    3311             : 
    3312          22 :             if (VSIRename(oTempFileSHX, osSHXName) != 0)
    3313             :             {
    3314           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3315           0 :                          "Can not rename new SHX file: %s", VSIStrerror(errno));
    3316           0 :                 return OGRERR_FAILURE;
    3317             :             }
    3318             : 
    3319          22 :             CheckFileDeletion(oTempFileSHP);
    3320          22 :             CheckFileDeletion(oTempFileSHX);
    3321             :         }
    3322             : 
    3323             :         /* --------------------------------------------------------------------
    3324             :          */
    3325             :         /*      Reopen the shapefile */
    3326             :         /*                                                                      */
    3327             :         /* We do not need to reimplement OGRShapeDataSource::OpenFile() here */
    3328             :         /* with the fully featured error checking. */
    3329             :         /* If all operations above succeeded, then all necessary files are */
    3330             :         /* in the right place and accessible. */
    3331             :         /* --------------------------------------------------------------------
    3332             :          */
    3333             : 
    3334          29 :         const char *const pszAccess = m_bUpdateAccess ? "r+" : "r";
    3335             : 
    3336          29 :         if (bMustReopenSHP)
    3337          22 :             m_hSHP = m_poDS->DS_SHPOpen(osSHPName, pszAccess);
    3338          29 :         if (bMustReopenDBF)
    3339          23 :             m_hDBF = m_poDS->DS_DBFOpen(osDBFName, pszAccess);
    3340             : 
    3341          29 :         if ((bMustReopenSHP && nullptr == m_hSHP) ||
    3342          23 :             (bMustReopenDBF && nullptr == m_hDBF))
    3343           0 :             return OGRERR_FAILURE;
    3344             :     }
    3345             : 
    3346             :     /* -------------------------------------------------------------------- */
    3347             :     /*      Update total shape count.                                       */
    3348             :     /* -------------------------------------------------------------------- */
    3349          30 :     if (m_hDBF != nullptr)
    3350          30 :         m_nTotalShapeCount = m_hDBF->nRecords;
    3351          30 :     m_bSHPNeedsRepack = false;
    3352          30 :     m_eNeedRepack = NO;
    3353             : 
    3354          30 :     return OGRERR_NONE;
    3355             : }
    3356             : 
    3357             : /************************************************************************/
    3358             : /*                               ResizeDBF()                            */
    3359             : /*                                                                      */
    3360             : /*      Autoshrink columns of the DBF file to their minimum             */
    3361             : /*      size, according to the existing data.                           */
    3362             : /************************************************************************/
    3363             : 
    3364           2 : OGRErr OGRShapeLayer::ResizeDBF()
    3365             : 
    3366             : {
    3367           2 :     if (!StartUpdate("ResizeDBF"))
    3368           0 :         return OGRERR_FAILURE;
    3369             : 
    3370           2 :     if (m_hDBF == nullptr)
    3371             :     {
    3372           0 :         CPLError(
    3373             :             CE_Failure, CPLE_NotSupported,
    3374             :             "Attempt to RESIZE a shapefile with no .dbf file not supported.");
    3375           0 :         return OGRERR_FAILURE;
    3376             :     }
    3377             : 
    3378             :     /* Look which columns must be examined */
    3379             :     int *panColMap = static_cast<int *>(
    3380           2 :         CPLMalloc(m_poFeatureDefn->GetFieldCount() * sizeof(int)));
    3381             :     int *panBestWidth = static_cast<int *>(
    3382           2 :         CPLMalloc(m_poFeatureDefn->GetFieldCount() * sizeof(int)));
    3383           2 :     int nStringCols = 0;
    3384           8 :     for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
    3385             :     {
    3386          10 :         if (m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTString ||
    3387          10 :             m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTInteger ||
    3388           0 :             m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTInteger64)
    3389             :         {
    3390           6 :             panColMap[nStringCols] = i;
    3391           6 :             panBestWidth[nStringCols] = 1;
    3392           6 :             nStringCols++;
    3393             :         }
    3394             :     }
    3395             : 
    3396           2 :     if (nStringCols == 0)
    3397             :     {
    3398             :         // Nothing to do.
    3399           0 :         CPLFree(panColMap);
    3400           0 :         CPLFree(panBestWidth);
    3401           0 :         return OGRERR_NONE;
    3402             :     }
    3403             : 
    3404           2 :     CPLDebug("SHAPE", "Computing optimal column size...");
    3405             : 
    3406           2 :     bool bAlreadyWarned = false;
    3407           8 :     for (int i = 0; i < m_hDBF->nRecords; i++)
    3408             :     {
    3409           6 :         if (!DBFIsRecordDeleted(m_hDBF, i))
    3410             :         {
    3411          24 :             for (int j = 0; j < nStringCols; j++)
    3412             :             {
    3413          18 :                 if (DBFIsAttributeNULL(m_hDBF, i, panColMap[j]))
    3414           6 :                     continue;
    3415             : 
    3416             :                 const char *pszVal =
    3417          12 :                     DBFReadStringAttribute(m_hDBF, i, panColMap[j]);
    3418          12 :                 const int nLen = static_cast<int>(strlen(pszVal));
    3419          12 :                 if (nLen > panBestWidth[j])
    3420           6 :                     panBestWidth[j] = nLen;
    3421             :             }
    3422             :         }
    3423           0 :         else if (!bAlreadyWarned)
    3424             :         {
    3425           0 :             bAlreadyWarned = true;
    3426           0 :             CPLDebug(
    3427             :                 "SHAPE",
    3428             :                 "DBF file would also need a REPACK due to deleted records");
    3429             :         }
    3430             :     }
    3431             : 
    3432           8 :     for (int j = 0; j < nStringCols; j++)
    3433             :     {
    3434           6 :         const int iField = panColMap[j];
    3435           6 :         OGRFieldDefn *const poFieldDefn = m_poFeatureDefn->GetFieldDefn(iField);
    3436             : 
    3437           6 :         const char chNativeType = DBFGetNativeFieldType(m_hDBF, iField);
    3438           6 :         char szFieldName[XBASE_FLDNAME_LEN_READ + 1] = {};
    3439           6 :         int nOriWidth = 0;
    3440           6 :         int nPrecision = 0;
    3441           6 :         DBFGetFieldInfo(m_hDBF, iField, szFieldName, &nOriWidth, &nPrecision);
    3442             : 
    3443           6 :         if (panBestWidth[j] < nOriWidth)
    3444             :         {
    3445           3 :             CPLDebug("SHAPE",
    3446             :                      "Shrinking field %d (%s) from %d to %d characters", iField,
    3447           3 :                      poFieldDefn->GetNameRef(), nOriWidth, panBestWidth[j]);
    3448             : 
    3449           3 :             if (!DBFAlterFieldDefn(m_hDBF, iField, szFieldName, chNativeType,
    3450           3 :                                    panBestWidth[j], nPrecision))
    3451             :             {
    3452           0 :                 CPLError(
    3453             :                     CE_Failure, CPLE_AppDefined,
    3454             :                     "Shrinking field %d (%s) from %d to %d characters failed",
    3455             :                     iField, poFieldDefn->GetNameRef(), nOriWidth,
    3456           0 :                     panBestWidth[j]);
    3457             : 
    3458           0 :                 CPLFree(panColMap);
    3459           0 :                 CPLFree(panBestWidth);
    3460             : 
    3461           0 :                 return OGRERR_FAILURE;
    3462             :             }
    3463             :             else
    3464             :             {
    3465           3 :                 whileUnsealing(poFieldDefn)->SetWidth(panBestWidth[j]);
    3466             :             }
    3467             :         }
    3468             :     }
    3469             : 
    3470           2 :     TruncateDBF();
    3471             : 
    3472           2 :     CPLFree(panColMap);
    3473           2 :     CPLFree(panBestWidth);
    3474             : 
    3475           2 :     return OGRERR_NONE;
    3476             : }
    3477             : 
    3478             : /************************************************************************/
    3479             : /*                          TruncateDBF()                               */
    3480             : /************************************************************************/
    3481             : 
    3482          23 : void OGRShapeLayer::TruncateDBF()
    3483             : {
    3484          23 :     if (m_hDBF == nullptr)
    3485           0 :         return;
    3486             : 
    3487          23 :     m_hDBF->sHooks.FSeek(m_hDBF->fp, 0, SEEK_END);
    3488          23 :     vsi_l_offset nOldSize = m_hDBF->sHooks.FTell(m_hDBF->fp);
    3489          23 :     vsi_l_offset nNewSize =
    3490          23 :         m_hDBF->nRecordLength * static_cast<SAOffset>(m_hDBF->nRecords) +
    3491          23 :         m_hDBF->nHeaderLength;
    3492          23 :     if (m_hDBF->bWriteEndOfFileChar)
    3493          20 :         nNewSize++;
    3494          23 :     if (nNewSize < nOldSize)
    3495             :     {
    3496          12 :         CPLDebug("SHAPE",
    3497             :                  "Truncating DBF file from " CPL_FRMT_GUIB " to " CPL_FRMT_GUIB
    3498             :                  " bytes",
    3499             :                  nOldSize, nNewSize);
    3500          12 :         VSIFTruncateL(VSI_SHP_GetVSIL(m_hDBF->fp), nNewSize);
    3501             :     }
    3502          23 :     m_hDBF->sHooks.FSeek(m_hDBF->fp, 0, SEEK_SET);
    3503             : }
    3504             : 
    3505             : /************************************************************************/
    3506             : /*                        RecomputeExtent()                             */
    3507             : /*                                                                      */
    3508             : /*      Force recomputation of the extent of the .SHP file              */
    3509             : /************************************************************************/
    3510             : 
    3511           5 : OGRErr OGRShapeLayer::RecomputeExtent()
    3512             : {
    3513           5 :     if (!StartUpdate("RecomputeExtent"))
    3514           1 :         return OGRERR_FAILURE;
    3515             : 
    3516           4 :     if (m_hSHP == nullptr)
    3517             :     {
    3518           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3519             :                  "The RECOMPUTE EXTENT operation is not permitted on a layer "
    3520             :                  "without .SHP file.");
    3521           0 :         return OGRERR_FAILURE;
    3522             :     }
    3523             : 
    3524           4 :     double adBoundsMin[4] = {0.0, 0.0, 0.0, 0.0};
    3525           4 :     double adBoundsMax[4] = {0.0, 0.0, 0.0, 0.0};
    3526             : 
    3527           4 :     bool bHasBeenInit = false;
    3528             : 
    3529          34 :     for (int iShape = 0; iShape < m_nTotalShapeCount; iShape++)
    3530             :     {
    3531          30 :         if (m_hDBF == nullptr || !DBFIsRecordDeleted(m_hDBF, iShape))
    3532             :         {
    3533          30 :             SHPObject *psObject = SHPReadObject(m_hSHP, iShape);
    3534          30 :             if (psObject != nullptr && psObject->nSHPType != SHPT_NULL &&
    3535          29 :                 psObject->nVertices != 0)
    3536             :             {
    3537          29 :                 if (!bHasBeenInit)
    3538             :                 {
    3539           4 :                     bHasBeenInit = true;
    3540           4 :                     adBoundsMin[0] = psObject->padfX[0];
    3541           4 :                     adBoundsMax[0] = psObject->padfX[0];
    3542           4 :                     adBoundsMin[1] = psObject->padfY[0];
    3543           4 :                     adBoundsMax[1] = psObject->padfY[0];
    3544           4 :                     if (psObject->padfZ)
    3545             :                     {
    3546           3 :                         adBoundsMin[2] = psObject->padfZ[0];
    3547           3 :                         adBoundsMax[2] = psObject->padfZ[0];
    3548             :                     }
    3549           4 :                     if (psObject->padfM)
    3550             :                     {
    3551           2 :                         adBoundsMin[3] = psObject->padfM[0];
    3552           2 :                         adBoundsMax[3] = psObject->padfM[0];
    3553             :                     }
    3554             :                 }
    3555             : 
    3556          66 :                 for (int i = 0; i < psObject->nVertices; i++)
    3557             :                 {
    3558          37 :                     adBoundsMin[0] =
    3559          37 :                         std::min(adBoundsMin[0], psObject->padfX[i]);
    3560          37 :                     adBoundsMin[1] =
    3561          37 :                         std::min(adBoundsMin[1], psObject->padfY[i]);
    3562          37 :                     adBoundsMax[0] =
    3563          37 :                         std::max(adBoundsMax[0], psObject->padfX[i]);
    3564          37 :                     adBoundsMax[1] =
    3565          37 :                         std::max(adBoundsMax[1], psObject->padfY[i]);
    3566          37 :                     if (psObject->padfZ)
    3567             :                     {
    3568          32 :                         adBoundsMin[2] =
    3569          32 :                             std::min(adBoundsMin[2], psObject->padfZ[i]);
    3570          32 :                         adBoundsMax[2] =
    3571          32 :                             std::max(adBoundsMax[2], psObject->padfZ[i]);
    3572             :                     }
    3573          37 :                     if (psObject->padfM)
    3574             :                     {
    3575          27 :                         adBoundsMax[3] =
    3576          27 :                             std::max(adBoundsMax[3], psObject->padfM[i]);
    3577          27 :                         adBoundsMin[3] =
    3578          27 :                             std::min(adBoundsMin[3], psObject->padfM[i]);
    3579             :                     }
    3580             :                 }
    3581             :             }
    3582          30 :             SHPDestroyObject(psObject);
    3583             :         }
    3584             :     }
    3585             : 
    3586           4 :     if (memcmp(m_hSHP->adBoundsMin, adBoundsMin, 4 * sizeof(double)) != 0 ||
    3587           1 :         memcmp(m_hSHP->adBoundsMax, adBoundsMax, 4 * sizeof(double)) != 0)
    3588             :     {
    3589           3 :         m_bHeaderDirty = true;
    3590           3 :         m_hSHP->bUpdated = TRUE;
    3591           3 :         memcpy(m_hSHP->adBoundsMin, adBoundsMin, 4 * sizeof(double));
    3592           3 :         memcpy(m_hSHP->adBoundsMax, adBoundsMax, 4 * sizeof(double));
    3593             :     }
    3594             : 
    3595           4 :     return OGRERR_NONE;
    3596             : }
    3597             : 
    3598             : /************************************************************************/
    3599             : /*                              TouchLayer()                            */
    3600             : /************************************************************************/
    3601             : 
    3602      238889 : bool OGRShapeLayer::TouchLayer()
    3603             : {
    3604      238889 :     m_poDS->SetLastUsedLayer(this);
    3605             : 
    3606      238889 :     if (m_eFileDescriptorsState == FD_OPENED)
    3607      235883 :         return true;
    3608        3006 :     if (m_eFileDescriptorsState == FD_CANNOT_REOPEN)
    3609           0 :         return false;
    3610             : 
    3611        3006 :     return ReopenFileDescriptors();
    3612             : }
    3613             : 
    3614             : /************************************************************************/
    3615             : /*                        ReopenFileDescriptors()                       */
    3616             : /************************************************************************/
    3617             : 
    3618        3010 : bool OGRShapeLayer::ReopenFileDescriptors()
    3619             : {
    3620        3010 :     CPLDebug("SHAPE", "ReopenFileDescriptors(%s)", m_osFullName.c_str());
    3621             : 
    3622             :     const bool bRealUpdateAccess =
    3623        4519 :         m_bUpdateAccess &&
    3624        1509 :         (!m_poDS->IsZip() || !m_poDS->GetTemporaryUnzipDir().empty());
    3625             : 
    3626        3010 :     if (m_bHSHPWasNonNULL)
    3627             :     {
    3628        3010 :         m_hSHP = m_poDS->DS_SHPOpen(m_osFullName.c_str(),
    3629             :                                     bRealUpdateAccess ? "r+" : "r");
    3630             : 
    3631        3010 :         if (m_hSHP == nullptr)
    3632             :         {
    3633           0 :             m_eFileDescriptorsState = FD_CANNOT_REOPEN;
    3634           0 :             return false;
    3635             :         }
    3636             :     }
    3637             : 
    3638        3010 :     if (m_bHDBFWasNonNULL)
    3639             :     {
    3640        3009 :         m_hDBF = m_poDS->DS_DBFOpen(m_osFullName.c_str(),
    3641             :                                     bRealUpdateAccess ? "r+" : "r");
    3642             : 
    3643        3009 :         if (m_hDBF == nullptr)
    3644             :         {
    3645           0 :             CPLError(
    3646             :                 CE_Failure, CPLE_OpenFailed, "Cannot reopen %s",
    3647           0 :                 CPLResetExtensionSafe(m_osFullName.c_str(), "dbf").c_str());
    3648           0 :             m_eFileDescriptorsState = FD_CANNOT_REOPEN;
    3649           0 :             return false;
    3650             :         }
    3651             :     }
    3652             : 
    3653        3010 :     m_eFileDescriptorsState = FD_OPENED;
    3654             : 
    3655        3010 :     return true;
    3656             : }
    3657             : 
    3658             : /************************************************************************/
    3659             : /*                        CloseUnderlyingLayer()                        */
    3660             : /************************************************************************/
    3661             : 
    3662        5811 : void OGRShapeLayer::CloseUnderlyingLayer()
    3663             : {
    3664        5811 :     CPLDebug("SHAPE", "CloseUnderlyingLayer(%s)", m_osFullName.c_str());
    3665             : 
    3666        5811 :     if (m_hDBF != nullptr)
    3667        5809 :         DBFClose(m_hDBF);
    3668        5811 :     m_hDBF = nullptr;
    3669             : 
    3670        5811 :     if (m_hSHP != nullptr)
    3671        5811 :         SHPClose(m_hSHP);
    3672        5811 :     m_hSHP = nullptr;
    3673             : 
    3674             :     // We close QIX and reset the check flag, so that CheckForQIX()
    3675             :     // will retry opening it if necessary when the layer is active again.
    3676        5811 :     if (m_hQIX != nullptr)
    3677           0 :         SHPCloseDiskTree(m_hQIX);
    3678        5811 :     m_hQIX = nullptr;
    3679        5811 :     m_bCheckedForQIX = false;
    3680             : 
    3681        5811 :     if (m_hSBN != nullptr)
    3682           0 :         SBNCloseDiskTree(m_hSBN);
    3683        5811 :     m_hSBN = nullptr;
    3684        5811 :     m_bCheckedForSBN = false;
    3685             : 
    3686        5811 :     m_eFileDescriptorsState = FD_CLOSED;
    3687        5811 : }
    3688             : 
    3689             : /************************************************************************/
    3690             : /*                            AddToFileList()                           */
    3691             : /************************************************************************/
    3692             : 
    3693         142 : void OGRShapeLayer::AddToFileList(CPLStringList &oFileList)
    3694             : {
    3695         142 :     if (!TouchLayer())
    3696           0 :         return;
    3697             : 
    3698         142 :     if (m_hSHP)
    3699             :     {
    3700          18 :         const char *pszSHPFilename = VSI_SHP_GetFilename(m_hSHP->fpSHP);
    3701          18 :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(pszSHPFilename));
    3702          36 :         const std::string osSHPExt = CPLGetExtensionSafe(pszSHPFilename);
    3703             :         const std::string osSHXFilename = CPLResetExtensionSafe(
    3704          36 :             pszSHPFilename, (osSHPExt[0] == 's') ? "shx" : "SHX");
    3705             :         oFileList.AddStringDirectly(
    3706          18 :             VSIGetCanonicalFilename(osSHXFilename.c_str()));
    3707             :     }
    3708             : 
    3709         142 :     if (m_hDBF)
    3710             :     {
    3711         141 :         const char *pszDBFFilename = VSI_SHP_GetFilename(m_hDBF->fp);
    3712         141 :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(pszDBFFilename));
    3713         141 :         if (m_hDBF->pszCodePage != nullptr && m_hDBF->iLanguageDriver == 0)
    3714             :         {
    3715           0 :             const std::string osDBFExt = CPLGetExtensionSafe(pszDBFFilename);
    3716             :             const std::string osCPGFilename = CPLResetExtensionSafe(
    3717           0 :                 pszDBFFilename, (osDBFExt[0] == 'd') ? "cpg" : "CPG");
    3718             :             oFileList.AddStringDirectly(
    3719           0 :                 VSIGetCanonicalFilename(osCPGFilename.c_str()));
    3720             :         }
    3721             :     }
    3722             : 
    3723         142 :     if (m_hSHP)
    3724             :     {
    3725          18 :         if (GetSpatialRef() != nullptr)
    3726             :         {
    3727             :             const OGRShapeGeomFieldDefn *poGeomFieldDefn =
    3728          10 :                 cpl::down_cast<const OGRShapeGeomFieldDefn *>(
    3729          10 :                     GetLayerDefn()->GetGeomFieldDefn(0));
    3730             :             oFileList.AddStringDirectly(
    3731          10 :                 VSIGetCanonicalFilename(poGeomFieldDefn->GetPrjFilename()));
    3732             :         }
    3733          18 :         if (CheckForQIX())
    3734             :         {
    3735             :             const std::string osQIXFilename =
    3736           4 :                 CPLResetExtensionSafe(m_osFullName.c_str(), "qix");
    3737             :             oFileList.AddStringDirectly(
    3738           2 :                 VSIGetCanonicalFilename(osQIXFilename.c_str()));
    3739             :         }
    3740          16 :         else if (CheckForSBN())
    3741             :         {
    3742             :             const std::string osSBNFilename =
    3743           2 :                 CPLResetExtensionSafe(m_osFullName.c_str(), "sbn");
    3744             :             oFileList.AddStringDirectly(
    3745           1 :                 VSIGetCanonicalFilename(osSBNFilename.c_str()));
    3746             :             const std::string osSBXFilename =
    3747           2 :                 CPLResetExtensionSafe(m_osFullName.c_str(), "sbx");
    3748             :             oFileList.AddStringDirectly(
    3749           1 :                 VSIGetCanonicalFilename(osSBXFilename.c_str()));
    3750             :         }
    3751             :     }
    3752             : 
    3753         142 :     if (m_bHasShpXML)
    3754             :     {
    3755             :         const std::string osSBXFilename =
    3756           2 :             CPLResetExtensionSafe(m_osFullName.c_str(), "shp.xml");
    3757             :         oFileList.AddStringDirectly(
    3758           1 :             VSIGetCanonicalFilename(osSBXFilename.c_str()));
    3759             :     }
    3760             : }
    3761             : 
    3762             : /************************************************************************/
    3763             : /*                   UpdateFollowingDeOrRecompression()                 */
    3764             : /************************************************************************/
    3765             : 
    3766           3 : void OGRShapeLayer::UpdateFollowingDeOrRecompression()
    3767             : {
    3768           3 :     CPLAssert(m_poDS->IsZip());
    3769           6 :     CPLString osDSDir = m_poDS->GetTemporaryUnzipDir();
    3770           3 :     if (osDSDir.empty())
    3771           0 :         osDSDir = m_poDS->GetVSIZipPrefixeDir();
    3772             : 
    3773           3 :     if (GetSpatialRef() != nullptr)
    3774             :     {
    3775             :         OGRShapeGeomFieldDefn *poGeomFieldDefn =
    3776           3 :             cpl::down_cast<OGRShapeGeomFieldDefn *>(
    3777           3 :                 GetLayerDefn()->GetGeomFieldDefn(0));
    3778           9 :         poGeomFieldDefn->SetPrjFilename(
    3779           6 :             CPLFormFilenameSafe(
    3780             :                 osDSDir.c_str(),
    3781           3 :                 CPLGetFilename(poGeomFieldDefn->GetPrjFilename().c_str()),
    3782             :                 nullptr)
    3783             :                 .c_str());
    3784             :     }
    3785             : 
    3786           6 :     m_osFullName = CPLFormFilenameSafe(
    3787           3 :         osDSDir, CPLGetFilename(m_osFullName.c_str()), nullptr);
    3788           3 :     CloseUnderlyingLayer();
    3789           3 : }
    3790             : 
    3791             : /************************************************************************/
    3792             : /*                           Rename()                                   */
    3793             : /************************************************************************/
    3794             : 
    3795           7 : OGRErr OGRShapeLayer::Rename(const char *pszNewName)
    3796             : {
    3797           7 :     if (!TestCapability(OLCRename))
    3798           0 :         return OGRERR_FAILURE;
    3799             : 
    3800           7 :     if (CPLLaunderForFilenameSafe(pszNewName, nullptr) != pszNewName)
    3801             :     {
    3802           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    3803             :                  "Illegal characters in '%s' to form a valid filename",
    3804             :                  pszNewName);
    3805           1 :         return OGRERR_FAILURE;
    3806             :     }
    3807             : 
    3808           6 :     if (m_poDS->GetLayerByName(pszNewName) != nullptr)
    3809             :     {
    3810           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Layer %s already exists",
    3811             :                  pszNewName);
    3812           1 :         return OGRERR_FAILURE;
    3813             :     }
    3814             : 
    3815           5 :     if (!m_poDS->UncompressIfNeeded())
    3816           0 :         return OGRERR_FAILURE;
    3817             : 
    3818          10 :     CPLStringList oFileList;
    3819           5 :     AddToFileList(oFileList);
    3820             : 
    3821          10 :     const std::string osDirname = CPLGetPathSafe(m_osFullName.c_str());
    3822          23 :     for (int i = 0; i < oFileList.size(); ++i)
    3823             :     {
    3824             :         const std::string osRenamedFile =
    3825             :             CPLFormFilenameSafe(osDirname.c_str(), pszNewName,
    3826          19 :                                 CPLGetExtensionSafe(oFileList[i]).c_str());
    3827             :         VSIStatBufL sStat;
    3828          19 :         if (VSIStatL(osRenamedFile.c_str(), &sStat) == 0)
    3829             :         {
    3830           1 :             CPLError(CE_Failure, CPLE_AppDefined, "File %s already exists",
    3831             :                      osRenamedFile.c_str());
    3832           1 :             return OGRERR_FAILURE;
    3833             :         }
    3834             :     }
    3835             : 
    3836           4 :     CloseUnderlyingLayer();
    3837             : 
    3838          20 :     for (int i = 0; i < oFileList.size(); ++i)
    3839             :     {
    3840             :         const std::string osRenamedFile =
    3841             :             CPLFormFilenameSafe(osDirname.c_str(), pszNewName,
    3842          16 :                                 CPLGetExtensionSafe(oFileList[i]).c_str());
    3843          16 :         if (VSIRename(oFileList[i], osRenamedFile.c_str()) != 0)
    3844             :         {
    3845           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename %s to %s",
    3846             :                      oFileList[i], osRenamedFile.c_str());
    3847           0 :             return OGRERR_FAILURE;
    3848             :         }
    3849             :     }
    3850             : 
    3851           4 :     if (GetSpatialRef() != nullptr)
    3852             :     {
    3853             :         OGRShapeGeomFieldDefn *poGeomFieldDefn =
    3854           4 :             cpl::down_cast<OGRShapeGeomFieldDefn *>(
    3855           4 :                 GetLayerDefn()->GetGeomFieldDefn(0));
    3856          12 :         poGeomFieldDefn->SetPrjFilename(
    3857           8 :             CPLFormFilenameSafe(
    3858             :                 osDirname.c_str(), pszNewName,
    3859           8 :                 CPLGetExtensionSafe(poGeomFieldDefn->GetPrjFilename().c_str())
    3860             :                     .c_str())
    3861             :                 .c_str());
    3862             :     }
    3863             : 
    3864             :     m_osFullName =
    3865           8 :         CPLFormFilenameSafe(osDirname.c_str(), pszNewName,
    3866          12 :                             CPLGetExtensionSafe(m_osFullName.c_str()).c_str());
    3867             : 
    3868           4 :     if (!ReopenFileDescriptors())
    3869           0 :         return OGRERR_FAILURE;
    3870             : 
    3871           4 :     SetDescription(pszNewName);
    3872           4 :     whileUnsealing(m_poFeatureDefn)->SetName(pszNewName);
    3873             : 
    3874           4 :     return OGRERR_NONE;
    3875             : }
    3876             : 
    3877             : /************************************************************************/
    3878             : /*                          GetDataset()                                */
    3879             : /************************************************************************/
    3880             : 
    3881          42 : GDALDataset *OGRShapeLayer::GetDataset()
    3882             : {
    3883          42 :     return m_poDS;
    3884             : }
    3885             : 
    3886             : /************************************************************************/
    3887             : /*                        GetNextArrowArray()                           */
    3888             : /************************************************************************/
    3889             : 
    3890             : // Specialized implementation restricted to situations where only retrieving
    3891             : // of FID values is asked (without filters)
    3892             : // In other cases, fall back to generic implementation.
    3893          46 : int OGRShapeLayer::GetNextArrowArray(struct ArrowArrayStream *stream,
    3894             :                                      struct ArrowArray *out_array)
    3895             : {
    3896          46 :     m_bLastGetNextArrowArrayUsedOptimizedCodePath = false;
    3897          46 :     if (!TouchLayer())
    3898             :     {
    3899           0 :         memset(out_array, 0, sizeof(*out_array));
    3900           0 :         return EIO;
    3901             :     }
    3902             : 
    3903          46 :     if (!m_hDBF || m_poAttrQuery != nullptr || m_poFilterGeom != nullptr)
    3904             :     {
    3905          21 :         return OGRLayer::GetNextArrowArray(stream, out_array);
    3906             :     }
    3907             : 
    3908             :     // If any field is not ignored, use generic implementation
    3909          25 :     const int nFieldCount = m_poFeatureDefn->GetFieldCount();
    3910          56 :     for (int i = 0; i < nFieldCount; ++i)
    3911             :     {
    3912          45 :         if (!m_poFeatureDefn->GetFieldDefn(i)->IsIgnored())
    3913          14 :             return OGRLayer::GetNextArrowArray(stream, out_array);
    3914             :     }
    3915          22 :     if (GetGeomType() != wkbNone &&
    3916          11 :         !m_poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored())
    3917           2 :         return OGRLayer::GetNextArrowArray(stream, out_array);
    3918             : 
    3919           9 :     OGRArrowArrayHelper sHelper(m_poDS, m_poFeatureDefn,
    3920          18 :                                 m_aosArrowArrayStreamOptions, out_array);
    3921           9 :     if (out_array->release == nullptr)
    3922             :     {
    3923           0 :         return ENOMEM;
    3924             :     }
    3925             : 
    3926           9 :     if (!sHelper.m_bIncludeFID)
    3927             :     {
    3928           1 :         out_array->release(out_array);
    3929           1 :         return OGRLayer::GetNextArrowArray(stream, out_array);
    3930             :     }
    3931             : 
    3932           8 :     m_bLastGetNextArrowArrayUsedOptimizedCodePath = true;
    3933           8 :     int nCount = 0;
    3934          34 :     while (m_iNextShapeId < m_nTotalShapeCount)
    3935             :     {
    3936             :         const bool bIsDeleted =
    3937          28 :             CPL_TO_BOOL(DBFIsRecordDeleted(m_hDBF, m_iNextShapeId));
    3938          28 :         if (bIsDeleted)
    3939             :         {
    3940           1 :             ++m_iNextShapeId;
    3941           1 :             continue;
    3942             :         }
    3943          53 :         if (VSIFEofL(VSI_SHP_GetVSIL(m_hDBF->fp)) ||
    3944          26 :             VSIFErrorL(VSI_SHP_GetVSIL(m_hDBF->fp)))
    3945             :         {
    3946           1 :             out_array->release(out_array);
    3947           1 :             memset(out_array, 0, sizeof(*out_array));
    3948           1 :             return EIO;
    3949             :         }
    3950          26 :         sHelper.m_panFIDValues[nCount] = m_iNextShapeId;
    3951          26 :         ++m_iNextShapeId;
    3952          26 :         ++nCount;
    3953          26 :         if (nCount == sHelper.m_nMaxBatchSize)
    3954           1 :             break;
    3955             :     }
    3956           7 :     sHelper.Shrink(nCount);
    3957           7 :     if (nCount == 0)
    3958             :     {
    3959           3 :         out_array->release(out_array);
    3960           3 :         memset(out_array, 0, sizeof(*out_array));
    3961             :     }
    3962           7 :     return 0;
    3963             : }
    3964             : 
    3965             : /************************************************************************/
    3966             : /*                        GetMetadataItem()                             */
    3967             : /************************************************************************/
    3968             : 
    3969         872 : const char *OGRShapeLayer::GetMetadataItem(const char *pszName,
    3970             :                                            const char *pszDomain)
    3971             : {
    3972         872 :     if (pszName && pszDomain && EQUAL(pszDomain, "__DEBUG__") &&
    3973          10 :         EQUAL(pszName, "LAST_GET_NEXT_ARROW_ARRAY_USED_OPTIMIZED_CODE_PATH"))
    3974             :     {
    3975          10 :         return m_bLastGetNextArrowArrayUsedOptimizedCodePath ? "YES" : "NO";
    3976             :     }
    3977         862 :     return OGRLayer::GetMetadataItem(pszName, pszDomain);
    3978             : }

Generated by: LCOV version 1.14