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