Coverage Report

Created: 2025-06-13 06:29

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