Coverage Report

Created: 2025-11-16 06:25

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