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 5928 : }
516 : }
517 : else
518 : {
519 0 : hDBF = nullptr;
520 : }
521 :
522 5928 : if (hDBF == nullptr && hSHP == nullptr)
523 0 : return false;
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* Create the layer object. */
527 : /* -------------------------------------------------------------------- */
528 : auto poLayer = std::make_unique<OGRShapeLayer>(
529 : this, pszNewName, hSHP, hDBF,
530 0 : /* poSRS = */ nullptr,
531 0 : /* bSRSSet = */ false,
532 5928 : /* osPrjFilename = */ std::string(), bUpdate, wkbNone, false);
533 11856 : poLayer->SetModificationDate(
534 5928 : CSLFetchNameValue(papszOpenOptions, "DBF_DATE_LAST_UPDATE"));
535 5928 : poLayer->SetAutoRepack(CPLFetchBool(papszOpenOptions, "AUTO_REPACK", true));
536 5928 : poLayer->SetWriteDBFEOFChar(
537 5928 : CPLFetchBool(papszOpenOptions, "DBF_EOF_CHAR", true));
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Add layer to data source layer list. */
541 : /* -------------------------------------------------------------------- */
542 5928 : AddLayer(std::move(poLayer));
543 :
544 5928 : return true;
545 : }
546 :
547 : /************************************************************************/
548 : /* AddLayer() */
549 : /************************************************************************/
550 :
551 7647 : void OGRShapeDataSource::AddLayer(std::unique_ptr<OGRShapeLayer> poLayer)
552 : {
553 7647 : m_apoLayers.push_back(std::move(poLayer));
554 :
555 : // If we reach the limit, then register all the already opened layers
556 : // Technically this code would not be necessary if there was not the
557 : // following initial test in SetLastUsedLayer() :
558 : // if (static_cast<int>(m_apoLayers.size()) < MAX_SIMULTANEOUSLY_OPENED_LAYERS)
559 : // return;
560 7647 : if (static_cast<int>(m_apoLayers.size()) ==
561 7654 : m_poPool->GetMaxSimultaneouslyOpened() &&
562 7 : m_poPool->GetSize() == 0)
563 : {
564 707 : for (auto &poIterLayer : m_apoLayers)
565 700 : m_poPool->SetLastUsedLayer(poIterLayer.get());
566 : }
567 7647 : }
568 :
569 : /************************************************************************/
570 : /* LaunderLayerName() */
571 : /************************************************************************/
572 :
573 1181 : static CPLString LaunderLayerName(const char *pszLayerName)
574 : {
575 2362 : std::string osRet(CPLLaunderForFilenameSafe(pszLayerName, nullptr));
576 1181 : if (osRet != pszLayerName)
577 : {
578 1 : CPLError(CE_Warning, CPLE_AppDefined,
579 : "Invalid layer name for a shapefile: %s. Laundered to %s.",
580 : pszLayerName, osRet.c_str());
581 : }
582 2362 : return osRet;
583 : }
584 :
585 : /************************************************************************/
586 : /* ICreateLayer() */
587 : /************************************************************************/
588 :
589 : OGRLayer *
590 1732 : OGRShapeDataSource::ICreateLayer(const char *pszLayerName,
591 : const OGRGeomFieldDefn *poGeomFieldDefn,
592 : CSLConstList papszOptions)
593 :
594 : {
595 : // To ensure that existing layers are created.
596 1732 : GetLayerCount();
597 :
598 1732 : auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
599 : const auto poSRS =
600 1732 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
601 :
602 : /* -------------------------------------------------------------------- */
603 : /* Check that the layer doesn't already exist. */
604 : /* -------------------------------------------------------------------- */
605 1732 : if (GetLayerByName(pszLayerName) != nullptr)
606 : {
607 2 : CPLError(CE_Failure, CPLE_AppDefined, "Layer '%s' already exists",
608 : pszLayerName);
609 2 : return nullptr;
610 : }
611 :
612 : /* -------------------------------------------------------------------- */
613 : /* Verify we are in update mode. */
614 : /* -------------------------------------------------------------------- */
615 1730 : if (eAccess == GA_ReadOnly)
616 : {
617 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
618 : "Data source %s opened read-only. "
619 : "New layer %s cannot be created.",
620 0 : GetDescription(), pszLayerName);
621 :
622 0 : return nullptr;
623 : }
624 :
625 1730 : if (m_bIsZip && m_bSingleLayerZip && m_apoLayers.size() == 1)
626 : {
627 1 : CPLError(CE_Failure, CPLE_NotSupported,
628 : ".shz only supports one single layer");
629 1 : return nullptr;
630 : }
631 :
632 1729 : if (!UncompressIfNeeded())
633 0 : return nullptr;
634 :
635 : /* -------------------------------------------------------------------- */
636 : /* Figure out what type of layer we need. */
637 : /* -------------------------------------------------------------------- */
638 1729 : int nShapeType = -1;
639 :
640 1729 : if (wkbFlatten(eType) == wkbUnknown || eType == wkbLineString)
641 1295 : nShapeType = SHPT_ARC;
642 434 : else if (eType == wkbPoint)
643 43 : nShapeType = SHPT_POINT;
644 391 : else if (eType == wkbPolygon || eType == wkbTriangle)
645 59 : nShapeType = SHPT_POLYGON;
646 332 : else if (eType == wkbMultiPoint)
647 7 : nShapeType = SHPT_MULTIPOINT;
648 325 : else if (eType == wkbPoint25D)
649 8 : nShapeType = SHPT_POINTZ;
650 317 : else if (eType == wkbPointM)
651 2 : nShapeType = SHPT_POINTM;
652 315 : else if (eType == wkbPointZM)
653 2 : nShapeType = SHPT_POINTZ;
654 313 : else if (eType == wkbLineString25D)
655 11 : nShapeType = SHPT_ARCZ;
656 302 : else if (eType == wkbLineStringM)
657 2 : nShapeType = SHPT_ARCM;
658 300 : else if (eType == wkbLineStringZM)
659 2 : nShapeType = SHPT_ARCZ;
660 298 : else if (eType == wkbMultiLineString)
661 18 : nShapeType = SHPT_ARC;
662 280 : else if (eType == wkbMultiLineString25D)
663 5 : nShapeType = SHPT_ARCZ;
664 275 : else if (eType == wkbMultiLineStringM)
665 1 : nShapeType = SHPT_ARCM;
666 274 : else if (eType == wkbMultiLineStringZM)
667 1 : nShapeType = SHPT_ARCZ;
668 273 : else if (eType == wkbPolygon25D || eType == wkbTriangleZ)
669 8 : nShapeType = SHPT_POLYGONZ;
670 265 : else if (eType == wkbPolygonM || eType == wkbTriangleM)
671 2 : nShapeType = SHPT_POLYGONM;
672 263 : else if (eType == wkbPolygonZM || eType == wkbTriangleZM)
673 2 : nShapeType = SHPT_POLYGONZ;
674 261 : else if (eType == wkbMultiPolygon)
675 166 : nShapeType = SHPT_POLYGON;
676 95 : else if (eType == wkbMultiPolygon25D)
677 8 : nShapeType = SHPT_POLYGONZ;
678 87 : else if (eType == wkbMultiPolygonM)
679 1 : nShapeType = SHPT_POLYGONM;
680 86 : else if (eType == wkbMultiPolygonZM)
681 1 : nShapeType = SHPT_POLYGONZ;
682 85 : else if (eType == wkbMultiPoint25D)
683 6 : nShapeType = SHPT_MULTIPOINTZ;
684 79 : else if (eType == wkbMultiPointM)
685 2 : nShapeType = SHPT_MULTIPOINTM;
686 77 : else if (eType == wkbMultiPointZM)
687 2 : nShapeType = SHPT_MULTIPOINTZ;
688 146 : else if (wkbFlatten(eType) == wkbTIN ||
689 71 : wkbFlatten(eType) == wkbPolyhedralSurface)
690 4 : nShapeType = SHPT_MULTIPATCH;
691 71 : else if (eType == wkbNone)
692 67 : nShapeType = SHPT_NULL;
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* Has the application overridden this with a special creation */
696 : /* option? */
697 : /* -------------------------------------------------------------------- */
698 1729 : const char *pszOverride = CSLFetchNameValue(papszOptions, "SHPT");
699 :
700 1729 : if (pszOverride == nullptr)
701 : {
702 : /* ignore */;
703 : }
704 28 : else if (EQUAL(pszOverride, "POINT"))
705 : {
706 1 : nShapeType = SHPT_POINT;
707 1 : eType = wkbPoint;
708 : }
709 27 : else if (EQUAL(pszOverride, "ARC"))
710 : {
711 2 : nShapeType = SHPT_ARC;
712 2 : eType = wkbLineString;
713 : }
714 25 : else if (EQUAL(pszOverride, "POLYGON"))
715 : {
716 2 : nShapeType = SHPT_POLYGON;
717 2 : eType = wkbPolygon;
718 : }
719 23 : else if (EQUAL(pszOverride, "MULTIPOINT"))
720 : {
721 1 : nShapeType = SHPT_MULTIPOINT;
722 1 : eType = wkbMultiPoint;
723 : }
724 22 : else if (EQUAL(pszOverride, "POINTZ"))
725 : {
726 1 : nShapeType = SHPT_POINTZ;
727 1 : eType = wkbPoint25D;
728 : }
729 21 : else if (EQUAL(pszOverride, "ARCZ"))
730 : {
731 2 : nShapeType = SHPT_ARCZ;
732 2 : eType = wkbLineString25D;
733 : }
734 19 : else if (EQUAL(pszOverride, "POLYGONZ"))
735 : {
736 4 : nShapeType = SHPT_POLYGONZ;
737 4 : eType = wkbPolygon25D;
738 : }
739 15 : else if (EQUAL(pszOverride, "MULTIPOINTZ"))
740 : {
741 1 : nShapeType = SHPT_MULTIPOINTZ;
742 1 : eType = wkbMultiPoint25D;
743 : }
744 14 : else if (EQUAL(pszOverride, "POINTM"))
745 : {
746 1 : nShapeType = SHPT_POINTM;
747 1 : eType = wkbPointM;
748 : }
749 13 : else if (EQUAL(pszOverride, "ARCM"))
750 : {
751 2 : nShapeType = SHPT_ARCM;
752 2 : eType = wkbLineStringM;
753 : }
754 11 : else if (EQUAL(pszOverride, "POLYGONM"))
755 : {
756 2 : nShapeType = SHPT_POLYGONM;
757 2 : eType = wkbPolygonM;
758 : }
759 9 : else if (EQUAL(pszOverride, "MULTIPOINTM"))
760 : {
761 1 : nShapeType = SHPT_MULTIPOINTM;
762 1 : eType = wkbMultiPointM;
763 : }
764 8 : else if (EQUAL(pszOverride, "POINTZM"))
765 : {
766 1 : nShapeType = SHPT_POINTZ;
767 1 : eType = wkbPointZM;
768 : }
769 7 : else if (EQUAL(pszOverride, "ARCZM"))
770 : {
771 2 : nShapeType = SHPT_ARCZ;
772 2 : eType = wkbLineStringZM;
773 : }
774 5 : else if (EQUAL(pszOverride, "POLYGONZM"))
775 : {
776 2 : nShapeType = SHPT_POLYGONZ;
777 2 : eType = wkbPolygonZM;
778 : }
779 3 : else if (EQUAL(pszOverride, "MULTIPOINTZM"))
780 : {
781 1 : nShapeType = SHPT_MULTIPOINTZ;
782 1 : eType = wkbMultiPointZM;
783 : }
784 2 : else if (EQUAL(pszOverride, "MULTIPATCH"))
785 : {
786 2 : nShapeType = SHPT_MULTIPATCH;
787 2 : eType = wkbUnknown; // not ideal...
788 : }
789 0 : else if (EQUAL(pszOverride, "NONE") || EQUAL(pszOverride, "NULL"))
790 : {
791 0 : nShapeType = SHPT_NULL;
792 0 : eType = wkbNone;
793 : }
794 : else
795 : {
796 0 : CPLError(CE_Failure, CPLE_NotSupported,
797 : "Unknown SHPT value of `%s' passed to Shapefile layer"
798 : "creation. Creation aborted.",
799 : pszOverride);
800 :
801 0 : return nullptr;
802 : }
803 :
804 1729 : if (nShapeType == -1)
805 : {
806 4 : CPLError(CE_Failure, CPLE_NotSupported,
807 : "Geometry type of `%s' not supported in shapefiles. "
808 : "Type can be overridden with a layer creation option "
809 : "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/"
810 : "MULTIPOINTZ/MULTIPATCH.",
811 : OGRGeometryTypeToName(eType));
812 4 : return nullptr;
813 : }
814 :
815 : /* -------------------------------------------------------------------- */
816 : /* What filename do we use, excluding the extension? */
817 : /* -------------------------------------------------------------------- */
818 3450 : std::string osFilenameWithoutExt;
819 :
820 1725 : if (m_bSingleFileDataSource && m_apoLayers.empty())
821 : {
822 1088 : const std::string osPath = CPLGetPathSafe(GetDescription());
823 544 : const std::string osFBasename = CPLGetBasenameSafe(GetDescription());
824 :
825 : osFilenameWithoutExt =
826 544 : CPLFormFilenameSafe(osPath.c_str(), osFBasename.c_str(), nullptr);
827 : }
828 1181 : else if (m_bSingleFileDataSource)
829 : {
830 : // This is a very weird use case : the user creates/open a datasource
831 : // made of a single shapefile 'foo.shp' and wants to add a new layer
832 : // to it, 'bar'. So we create a new shapefile 'bar.shp' in the same
833 : // directory as 'foo.shp'
834 : // So technically, we will not be any longer a single file
835 : // datasource ... Ahem ahem.
836 16 : const std::string osPath = CPLGetPathSafe(GetDescription());
837 32 : osFilenameWithoutExt = CPLFormFilenameSafe(
838 48 : osPath.c_str(), LaunderLayerName(pszLayerName).c_str(), nullptr);
839 : }
840 : else
841 : {
842 1165 : const std::string osDir(m_osTemporaryUnzipDir.empty()
843 1162 : ? std::string(GetDescription())
844 1165 : : m_osTemporaryUnzipDir);
845 2330 : osFilenameWithoutExt = CPLFormFilenameSafe(
846 3495 : osDir.c_str(), LaunderLayerName(pszLayerName).c_str(), nullptr);
847 : }
848 :
849 : /* -------------------------------------------------------------------- */
850 : /* Create the shapefile. */
851 : /* -------------------------------------------------------------------- */
852 : const bool l_b2GBLimit =
853 1725 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "2GB_LIMIT", "FALSE"));
854 :
855 1725 : SHPHandle hSHP = nullptr;
856 :
857 1725 : if (nShapeType != SHPT_NULL)
858 : {
859 : const std::string osFilename =
860 1658 : CPLFormFilenameSafe(nullptr, osFilenameWithoutExt.c_str(), "shp");
861 :
862 1658 : hSHP = SHPCreateLL(osFilename.c_str(), nShapeType,
863 : const_cast<SAHooks *>(VSI_SHP_GetHook(l_b2GBLimit)));
864 :
865 1658 : if (hSHP == nullptr)
866 : {
867 5 : return nullptr;
868 : }
869 :
870 1653 : SHPSetFastModeReadObject(hSHP, TRUE);
871 : }
872 :
873 : /* -------------------------------------------------------------------- */
874 : /* Has a specific LDID been specified by the caller? */
875 : /* -------------------------------------------------------------------- */
876 1720 : const char *pszLDID = CSLFetchNameValue(papszOptions, "ENCODING");
877 :
878 : /* -------------------------------------------------------------------- */
879 : /* Create a DBF file. */
880 : /* -------------------------------------------------------------------- */
881 : const std::string osDBFFilename =
882 3440 : CPLFormFilenameSafe(nullptr, osFilenameWithoutExt.c_str(), "dbf");
883 :
884 1720 : DBFHandle hDBF = DBFCreateLL(
885 : osDBFFilename.c_str(), (pszLDID != nullptr) ? pszLDID : "LDID/87",
886 1720 : const_cast<SAHooks *>(VSI_SHP_GetHook(m_b2GBLimit)));
887 :
888 1720 : if (hDBF == nullptr)
889 : {
890 1 : CPLError(CE_Failure, CPLE_OpenFailed,
891 : "Failed to create Shape DBF file `%s'.",
892 : osDBFFilename.c_str());
893 1 : SHPClose(hSHP);
894 1 : return nullptr;
895 : }
896 :
897 : /* -------------------------------------------------------------------- */
898 : /* Create the .prj file, if required. */
899 : /* -------------------------------------------------------------------- */
900 3438 : std::string osPrjFilename;
901 3438 : auto poSRSClone = OGRSpatialReferenceRefCountedPtr::makeClone(poSRS);
902 1719 : if (poSRSClone)
903 : {
904 : osPrjFilename =
905 254 : CPLFormFilenameSafe(nullptr, osFilenameWithoutExt.c_str(), "prj");
906 :
907 254 : char *pszWKT = nullptr;
908 254 : VSILFILE *fp = nullptr;
909 254 : const char *const apszOptions[] = {"FORMAT=WKT1_ESRI", nullptr};
910 504 : if (poSRSClone->exportToWkt(&pszWKT, apszOptions) == OGRERR_NONE &&
911 250 : (fp = VSIFOpenL(osPrjFilename.c_str(), "wt")) != nullptr)
912 : {
913 250 : VSIFWriteL(pszWKT, strlen(pszWKT), 1, fp);
914 250 : VSIFCloseL(fp);
915 : }
916 :
917 254 : CPLFree(pszWKT);
918 : }
919 :
920 : /* -------------------------------------------------------------------- */
921 : /* Create the layer object. */
922 : /* -------------------------------------------------------------------- */
923 : // OGRShapeLayer constructor expects a filename with an extension (that
924 : // could be random actually), otherwise this is going to cause problems with
925 : // layer names that have a dot (not speaking about the one before the shp)
926 : const std::string osSHPFilename =
927 3438 : CPLFormFilenameSafe(nullptr, osFilenameWithoutExt.c_str(), "shp");
928 :
929 : auto poLayer = std::make_unique<OGRShapeLayer>(
930 1719 : this, osSHPFilename.c_str(), hSHP, hDBF, poSRSClone.get(),
931 0 : /* bSRSSet = */ true, osPrjFilename,
932 5157 : /* bUpdate = */ true, eType, true);
933 :
934 1719 : poLayer->SetResizeAtClose(CPLFetchBool(papszOptions, "RESIZE", false));
935 1719 : poLayer->CreateSpatialIndexAtClose(
936 1719 : CPLFetchBool(papszOptions, "SPATIAL_INDEX", false));
937 1719 : poLayer->SetModificationDate(
938 : CSLFetchNameValue(papszOptions, "DBF_DATE_LAST_UPDATE"));
939 1719 : poLayer->SetAutoRepack(CPLFetchBool(papszOptions, "AUTO_REPACK", true));
940 1719 : poLayer->SetWriteDBFEOFChar(
941 1719 : CPLFetchBool(papszOptions, "DBF_EOF_CHAR", true));
942 :
943 : /* -------------------------------------------------------------------- */
944 : /* Add layer to data source layer list. */
945 : /* -------------------------------------------------------------------- */
946 1719 : AddLayer(std::move(poLayer));
947 :
948 1719 : return m_apoLayers.back().get();
949 : }
950 :
951 : /************************************************************************/
952 : /* TestCapability() */
953 : /************************************************************************/
954 :
955 958 : int OGRShapeDataSource::TestCapability(const char *pszCap) const
956 :
957 : {
958 958 : if (EQUAL(pszCap, ODsCCreateLayer))
959 452 : return eAccess == GA_Update &&
960 452 : !(m_bIsZip && m_bSingleLayerZip && m_apoLayers.size() == 1);
961 732 : else if (EQUAL(pszCap, ODsCDeleteLayer))
962 18 : return eAccess == GA_Update && !(m_bIsZip && m_bSingleLayerZip);
963 714 : else if (EQUAL(pszCap, ODsCMeasuredGeometries))
964 22 : return true;
965 692 : else if (EQUAL(pszCap, ODsCZGeometries))
966 22 : return true;
967 670 : else if (EQUAL(pszCap, ODsCRandomLayerWrite))
968 6 : return eAccess == GA_Update;
969 :
970 664 : return false;
971 : }
972 :
973 : /************************************************************************/
974 : /* GetLayerCount() */
975 : /************************************************************************/
976 :
977 609905 : int OGRShapeDataSource::GetLayerCount() const
978 :
979 : {
980 : #ifndef IMMEDIATE_OPENING
981 609905 : if (!m_oVectorLayerName.empty())
982 : {
983 4276 : for (size_t i = 0; i < m_oVectorLayerName.size(); i++)
984 : {
985 3926 : const char *pszFilename = m_oVectorLayerName[i].c_str();
986 3926 : const std::string osLayerName = CPLGetBasenameSafe(pszFilename);
987 :
988 3926 : bool bFound = false;
989 632264 : for (auto &poLayer : m_apoLayers)
990 : {
991 629580 : if (poLayer->GetName() == osLayerName)
992 : {
993 1242 : bFound = true;
994 1242 : break;
995 : }
996 : }
997 3926 : if (bFound)
998 1242 : continue;
999 :
1000 2684 : if (!const_cast<OGRShapeDataSource *>(this)->OpenFile(
1001 2684 : pszFilename, eAccess == GA_Update))
1002 : {
1003 1 : CPLError(CE_Failure, CPLE_OpenFailed,
1004 : "Failed to open file %s."
1005 : "It may be corrupt or read-only file accessed in "
1006 : "update mode.",
1007 : pszFilename);
1008 : }
1009 : }
1010 350 : m_oVectorLayerName.resize(0);
1011 : }
1012 : #endif
1013 :
1014 609905 : return static_cast<int>(m_apoLayers.size());
1015 : }
1016 :
1017 : /************************************************************************/
1018 : /* GetLayer() */
1019 : /************************************************************************/
1020 :
1021 552146 : const OGRLayer *OGRShapeDataSource::GetLayer(int iLayer) const
1022 :
1023 : {
1024 : // To ensure that existing layers are created.
1025 552146 : GetLayerCount();
1026 :
1027 552146 : if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
1028 14 : return nullptr;
1029 :
1030 552132 : return m_apoLayers[iLayer].get();
1031 : }
1032 :
1033 : /************************************************************************/
1034 : /* GetLayerByName() */
1035 : /************************************************************************/
1036 :
1037 5342 : OGRLayer *OGRShapeDataSource::GetLayerByName(const char *pszLayerNameIn)
1038 : {
1039 : #ifndef IMMEDIATE_OPENING
1040 5342 : if (!m_oVectorLayerName.empty())
1041 : {
1042 257267 : for (auto &poLayer : m_apoLayers)
1043 : {
1044 255930 : if (strcmp(poLayer->GetName(), pszLayerNameIn) == 0)
1045 : {
1046 1083 : return poLayer.get();
1047 : }
1048 : }
1049 :
1050 1439 : for (int j = 0; j < 2; j++)
1051 : {
1052 252109 : for (size_t i = 0; i < m_oVectorLayerName.size(); i++)
1053 : {
1054 252007 : const char *pszFilename = m_oVectorLayerName[i].c_str();
1055 252007 : const std::string osLayerName = CPLGetBasenameSafe(pszFilename);
1056 :
1057 252007 : if (j == 0)
1058 : {
1059 251896 : if (osLayerName != pszLayerNameIn)
1060 250655 : continue;
1061 : }
1062 : else
1063 : {
1064 111 : if (!EQUAL(osLayerName.c_str(), pszLayerNameIn))
1065 21 : continue;
1066 : }
1067 :
1068 1331 : if (!OpenFile(pszFilename, eAccess == GA_Update))
1069 : {
1070 1 : CPLError(CE_Failure, CPLE_OpenFailed,
1071 : "Failed to open file %s. "
1072 : "It may be corrupt or read-only file accessed in "
1073 : "update mode.",
1074 : pszFilename);
1075 1 : return nullptr;
1076 : }
1077 :
1078 1330 : return m_apoLayers.back().get();
1079 : }
1080 : }
1081 :
1082 6 : return nullptr;
1083 : }
1084 : #endif
1085 :
1086 2922 : return GDALDataset::GetLayerByName(pszLayerNameIn);
1087 : }
1088 :
1089 : /************************************************************************/
1090 : /* ExecuteSQL() */
1091 : /* */
1092 : /* We override this to provide special handling of CREATE */
1093 : /* SPATIAL INDEX commands. Support forms are: */
1094 : /* */
1095 : /* CREATE SPATIAL INDEX ON layer_name [DEPTH n] */
1096 : /* DROP SPATIAL INDEX ON layer_name */
1097 : /* REPACK layer_name */
1098 : /* RECOMPUTE EXTENT ON layer_name */
1099 : /************************************************************************/
1100 :
1101 1028 : OGRLayer *OGRShapeDataSource::ExecuteSQL(const char *pszStatement,
1102 : OGRGeometry *poSpatialFilter,
1103 : const char *pszDialect)
1104 :
1105 : {
1106 1028 : if (EQUAL(pszStatement, "UNCOMPRESS"))
1107 : {
1108 0 : CPL_IGNORE_RET_VAL(UncompressIfNeeded());
1109 0 : return nullptr;
1110 : }
1111 :
1112 1028 : if (EQUAL(pszStatement, "RECOMPRESS"))
1113 : {
1114 0 : RecompressIfNeeded(GetLayerNames());
1115 0 : return nullptr;
1116 : }
1117 : /* ==================================================================== */
1118 : /* Handle command to drop a spatial index. */
1119 : /* ==================================================================== */
1120 1028 : if (STARTS_WITH_CI(pszStatement, "REPACK "))
1121 : {
1122 : OGRShapeLayer *poLayer =
1123 17 : cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 7));
1124 :
1125 17 : if (poLayer != nullptr)
1126 : {
1127 17 : if (poLayer->Repack() != OGRERR_NONE)
1128 : {
1129 1 : CPLError(CE_Failure, CPLE_AppDefined,
1130 : "REPACK of layer '%s' failed.", pszStatement + 7);
1131 : }
1132 : }
1133 : else
1134 : {
1135 0 : CPLError(CE_Failure, CPLE_AppDefined,
1136 : "No such layer as '%s' in REPACK.", pszStatement + 7);
1137 : }
1138 17 : return nullptr;
1139 : }
1140 :
1141 : /* ==================================================================== */
1142 : /* Handle command to shrink columns to their minimum size. */
1143 : /* ==================================================================== */
1144 1011 : if (STARTS_WITH_CI(pszStatement, "RESIZE "))
1145 : {
1146 : OGRShapeLayer *poLayer =
1147 1 : cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 7));
1148 :
1149 1 : if (poLayer != nullptr)
1150 : {
1151 1 : poLayer->ResizeDBF();
1152 : }
1153 : else
1154 : {
1155 0 : CPLError(CE_Failure, CPLE_AppDefined,
1156 : "No such layer as '%s' in RESIZE.", pszStatement + 7);
1157 : }
1158 1 : return nullptr;
1159 : }
1160 :
1161 : /* ==================================================================== */
1162 : /* Handle command to recompute extent */
1163 : /* ==================================================================== */
1164 1010 : if (STARTS_WITH_CI(pszStatement, "RECOMPUTE EXTENT ON "))
1165 : {
1166 : OGRShapeLayer *poLayer =
1167 6 : cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 20));
1168 :
1169 6 : if (poLayer != nullptr)
1170 : {
1171 6 : poLayer->RecomputeExtent();
1172 : }
1173 : else
1174 : {
1175 0 : CPLError(CE_Failure, CPLE_AppDefined,
1176 : "No such layer as '%s' in RECOMPUTE EXTENT.",
1177 : pszStatement + 20);
1178 : }
1179 6 : return nullptr;
1180 : }
1181 :
1182 : /* ==================================================================== */
1183 : /* Handle command to drop a spatial index. */
1184 : /* ==================================================================== */
1185 1004 : if (STARTS_WITH_CI(pszStatement, "DROP SPATIAL INDEX ON "))
1186 : {
1187 : OGRShapeLayer *poLayer =
1188 3 : cpl::down_cast<OGRShapeLayer *>(GetLayerByName(pszStatement + 22));
1189 :
1190 3 : if (poLayer != nullptr)
1191 : {
1192 3 : poLayer->DropSpatialIndex();
1193 : }
1194 : else
1195 : {
1196 0 : CPLError(CE_Failure, CPLE_AppDefined,
1197 : "No such layer as '%s' in DROP SPATIAL INDEX.",
1198 : pszStatement + 22);
1199 : }
1200 3 : return nullptr;
1201 : }
1202 :
1203 : /* ==================================================================== */
1204 : /* Handle all commands except spatial index creation generically. */
1205 : /* ==================================================================== */
1206 1001 : if (!STARTS_WITH_CI(pszStatement, "CREATE SPATIAL INDEX ON "))
1207 : {
1208 985 : char **papszTokens = CSLTokenizeString(pszStatement);
1209 985 : if (CSLCount(papszTokens) >= 4 &&
1210 474 : (EQUAL(papszTokens[0], "CREATE") ||
1211 446 : EQUAL(papszTokens[0], "DROP")) &&
1212 1459 : EQUAL(papszTokens[1], "INDEX") && EQUAL(papszTokens[2], "ON"))
1213 : {
1214 : OGRShapeLayer *poLayer =
1215 38 : cpl::down_cast<OGRShapeLayer *>(GetLayerByName(papszTokens[3]));
1216 38 : if (poLayer != nullptr)
1217 38 : poLayer->InitializeIndexSupport(poLayer->GetFullName());
1218 : }
1219 985 : CSLDestroy(papszTokens);
1220 :
1221 985 : return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter,
1222 985 : pszDialect);
1223 : }
1224 :
1225 : /* -------------------------------------------------------------------- */
1226 : /* Parse into keywords. */
1227 : /* -------------------------------------------------------------------- */
1228 16 : char **papszTokens = CSLTokenizeString(pszStatement);
1229 :
1230 32 : if (CSLCount(papszTokens) < 5 || !EQUAL(papszTokens[0], "CREATE") ||
1231 16 : !EQUAL(papszTokens[1], "SPATIAL") || !EQUAL(papszTokens[2], "INDEX") ||
1232 48 : !EQUAL(papszTokens[3], "ON") || CSLCount(papszTokens) > 7 ||
1233 16 : (CSLCount(papszTokens) == 7 && !EQUAL(papszTokens[5], "DEPTH")))
1234 : {
1235 0 : CSLDestroy(papszTokens);
1236 0 : CPLError(CE_Failure, CPLE_AppDefined,
1237 : "Syntax error in CREATE SPATIAL INDEX command.\n"
1238 : "Was '%s'\n"
1239 : "Should be of form 'CREATE SPATIAL INDEX ON <table> "
1240 : "[DEPTH <n>]'",
1241 : pszStatement);
1242 0 : return nullptr;
1243 : }
1244 :
1245 : /* -------------------------------------------------------------------- */
1246 : /* Get depth if provided. */
1247 : /* -------------------------------------------------------------------- */
1248 16 : const int nDepth = CSLCount(papszTokens) == 7 ? atoi(papszTokens[6]) : 0;
1249 :
1250 : /* -------------------------------------------------------------------- */
1251 : /* What layer are we operating on. */
1252 : /* -------------------------------------------------------------------- */
1253 : OGRShapeLayer *poLayer =
1254 16 : cpl::down_cast<OGRShapeLayer *>(GetLayerByName(papszTokens[4]));
1255 :
1256 16 : if (poLayer == nullptr)
1257 : {
1258 0 : CPLError(CE_Failure, CPLE_AppDefined, "Layer %s not recognised.",
1259 0 : papszTokens[4]);
1260 0 : CSLDestroy(papszTokens);
1261 0 : return nullptr;
1262 : }
1263 :
1264 16 : CSLDestroy(papszTokens);
1265 :
1266 16 : poLayer->CreateSpatialIndex(nDepth);
1267 16 : return nullptr;
1268 : }
1269 :
1270 : /************************************************************************/
1271 : /* GetExtensionsForDeletion() */
1272 : /************************************************************************/
1273 :
1274 694 : const char *const *OGRShapeDataSource::GetExtensionsForDeletion()
1275 : {
1276 : static const char *const apszExtensions[] = {
1277 : "shp", "shx", "dbf", "sbn", "sbx", "prj",
1278 : "idm", "ind", "qix", "cpg", "shp.xml",
1279 : "qpj", // QGIS projection file
1280 : nullptr};
1281 694 : return apszExtensions;
1282 : }
1283 :
1284 : /************************************************************************/
1285 : /* DeleteLayer() */
1286 : /************************************************************************/
1287 :
1288 548 : OGRErr OGRShapeDataSource::DeleteLayer(int iLayer)
1289 :
1290 : {
1291 : /* -------------------------------------------------------------------- */
1292 : /* Verify we are in update mode. */
1293 : /* -------------------------------------------------------------------- */
1294 548 : if (eAccess != GA_Update)
1295 : {
1296 1 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1297 : "Data source %s opened read-only. "
1298 : "Layer %d cannot be deleted.",
1299 1 : GetDescription(), iLayer);
1300 :
1301 1 : return OGRERR_FAILURE;
1302 : }
1303 :
1304 : // To ensure that existing layers are created.
1305 547 : GetLayerCount();
1306 :
1307 547 : if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
1308 : {
1309 2 : CPLError(CE_Failure, CPLE_AppDefined,
1310 : "Layer %d not in legal range of 0 to %d.", iLayer,
1311 2 : static_cast<int>(m_apoLayers.size()) - 1);
1312 2 : return OGRERR_FAILURE;
1313 : }
1314 :
1315 545 : if (m_bIsZip && m_bSingleLayerZip)
1316 : {
1317 3 : CPLError(CE_Failure, CPLE_NotSupported,
1318 : ".shz does not support layer deletion");
1319 3 : return OGRERR_FAILURE;
1320 : }
1321 :
1322 542 : if (!UncompressIfNeeded())
1323 0 : return OGRERR_FAILURE;
1324 :
1325 542 : const std::string osLayerFilename = m_apoLayers[iLayer]->GetFullName();
1326 :
1327 542 : m_apoLayers.erase(m_apoLayers.begin() + iLayer);
1328 :
1329 : const char *const *papszExtensions =
1330 542 : OGRShapeDataSource::GetExtensionsForDeletion();
1331 7046 : for (int iExt = 0; papszExtensions[iExt] != nullptr; iExt++)
1332 : {
1333 : const std::string osFile = CPLResetExtensionSafe(
1334 13008 : osLayerFilename.c_str(), papszExtensions[iExt]);
1335 : VSIStatBufL sStatBuf;
1336 6504 : if (VSIStatL(osFile.c_str(), &sStatBuf) == 0)
1337 1621 : VSIUnlink(osFile.c_str());
1338 : }
1339 :
1340 542 : return OGRERR_NONE;
1341 : }
1342 :
1343 : /************************************************************************/
1344 : /* SetLastUsedLayer() */
1345 : /************************************************************************/
1346 :
1347 246902 : void OGRShapeDataSource::SetLastUsedLayer(OGRShapeLayer *poLayer)
1348 : {
1349 : // We could remove that check and things would still work in
1350 : // 99.99% cases.
1351 : // The only rationale for that test is to avoid breaking applications that
1352 : // would deal with layers of the same datasource in different threads. In
1353 : // GDAL < 1.9.0, this would work in most cases I can imagine as shapefile
1354 : // layers are pretty much independent from each others (although it has
1355 : // never been guaranteed to be a valid use case, and the shape driver is
1356 : // likely more the exception than the rule in permitting accessing layers
1357 : // from different threads !) Anyway the LRU list mechanism leaves the door
1358 : // open to concurrent accesses to it so when the datasource has not many
1359 : // layers, we don't try to build the LRU list to avoid concurrency issues. I
1360 : // haven't bothered making the analysis of how a mutex could be used to
1361 : // protect that (my intuition is that it would need to be placed at the
1362 : // beginning of OGRShapeLayer::TouchLayer() ).
1363 493804 : if (static_cast<int>(m_apoLayers.size()) <
1364 246902 : m_poPool->GetMaxSimultaneouslyOpened())
1365 233459 : return;
1366 :
1367 13443 : m_poPool->SetLastUsedLayer(poLayer);
1368 : }
1369 :
1370 : /************************************************************************/
1371 : // GetFileList() */
1372 : /************************************************************************/
1373 :
1374 35 : char **OGRShapeDataSource::GetFileList()
1375 : {
1376 35 : if (m_bIsZip)
1377 : {
1378 1 : return CSLAddString(nullptr, GetDescription());
1379 : }
1380 68 : CPLStringList oFileList;
1381 34 : GetLayerCount();
1382 175 : for (auto &poLayer : m_apoLayers)
1383 : {
1384 141 : poLayer->AddToFileList(oFileList);
1385 : }
1386 34 : return oFileList.StealList();
1387 : }
1388 :
1389 : /************************************************************************/
1390 : // RefreshLockFile() */
1391 : /************************************************************************/
1392 :
1393 0 : void OGRShapeDataSource::RefreshLockFile(void *_self)
1394 : {
1395 0 : OGRShapeDataSource *self = static_cast<OGRShapeDataSource *>(_self);
1396 0 : CPLAssert(self->m_psLockFile);
1397 0 : CPLAcquireMutex(self->m_poRefreshLockFileMutex, 1000);
1398 0 : self->m_bRefreshLockFileThreadStarted = true;
1399 0 : CPLCondSignal(self->m_poRefreshLockFileCond);
1400 0 : unsigned int nInc = 0;
1401 0 : while (!(self->m_bExitRefreshLockFileThread))
1402 : {
1403 0 : auto ret = CPLCondTimedWait(self->m_poRefreshLockFileCond,
1404 : self->m_poRefreshLockFileMutex,
1405 : self->m_dfRefreshLockDelay);
1406 0 : if (ret == COND_TIMED_WAIT_TIME_OUT)
1407 : {
1408 0 : CPLAssert(self->m_psLockFile);
1409 0 : VSIFSeekL(self->m_psLockFile, 0, SEEK_SET);
1410 0 : CPLString osTime;
1411 0 : nInc++;
1412 : osTime.Printf(CPL_FRMT_GUIB ", %u\n",
1413 0 : static_cast<GUIntBig>(time(nullptr)), nInc);
1414 0 : VSIFWriteL(osTime.data(), 1, osTime.size(), self->m_psLockFile);
1415 0 : VSIFFlushL(self->m_psLockFile);
1416 : }
1417 : }
1418 0 : CPLReleaseMutex(self->m_poRefreshLockFileMutex);
1419 0 : }
1420 :
1421 : /************************************************************************/
1422 : // RemoveLockFile() */
1423 : /************************************************************************/
1424 :
1425 3827 : void OGRShapeDataSource::RemoveLockFile()
1426 : {
1427 3827 : if (!m_psLockFile)
1428 3827 : return;
1429 :
1430 : // Ask the thread to terminate
1431 0 : CPLAcquireMutex(m_poRefreshLockFileMutex, 1000);
1432 0 : m_bExitRefreshLockFileThread = true;
1433 0 : CPLCondSignal(m_poRefreshLockFileCond);
1434 0 : CPLReleaseMutex(m_poRefreshLockFileMutex);
1435 0 : CPLJoinThread(m_hRefreshLockFileThread);
1436 0 : m_hRefreshLockFileThread = nullptr;
1437 :
1438 : // Close and remove lock file
1439 0 : VSIFCloseL(m_psLockFile);
1440 0 : m_psLockFile = nullptr;
1441 0 : CPLString osLockFile(GetDescription());
1442 0 : osLockFile += ".gdal.lock";
1443 0 : VSIUnlink(osLockFile);
1444 : }
1445 :
1446 : /************************************************************************/
1447 : // UncompressIfNeeded() */
1448 : /************************************************************************/
1449 :
1450 77082 : bool OGRShapeDataSource::UncompressIfNeeded()
1451 : {
1452 77082 : if (eAccess != GA_Update || !m_bIsZip || !m_osTemporaryUnzipDir.empty())
1453 77076 : return true;
1454 :
1455 6 : GetLayerCount();
1456 :
1457 0 : auto returnError = [this]()
1458 : {
1459 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot uncompress %s",
1460 0 : GetDescription());
1461 0 : return false;
1462 6 : };
1463 :
1464 6 : if (m_apoLayers.size() > 1)
1465 : {
1466 0 : CPLString osLockFile(GetDescription());
1467 0 : osLockFile += ".gdal.lock";
1468 : VSIStatBufL sStat;
1469 0 : if (VSIStatL(osLockFile, &sStat) == 0 &&
1470 0 : sStat.st_mtime > time(nullptr) - 2 * knREFRESH_LOCK_FILE_DELAY_SEC)
1471 : {
1472 0 : CPLError(CE_Failure, CPLE_AppDefined,
1473 : "Cannot edit %s. Another task is editing it",
1474 0 : GetDescription());
1475 0 : return false;
1476 : }
1477 0 : if (!m_poRefreshLockFileMutex)
1478 : {
1479 0 : m_poRefreshLockFileMutex = CPLCreateMutex();
1480 0 : if (!m_poRefreshLockFileMutex)
1481 0 : return false;
1482 0 : CPLReleaseMutex(m_poRefreshLockFileMutex);
1483 : }
1484 0 : if (!m_poRefreshLockFileCond)
1485 : {
1486 0 : m_poRefreshLockFileCond = CPLCreateCond();
1487 0 : if (!m_poRefreshLockFileCond)
1488 0 : return false;
1489 : }
1490 0 : auto f = VSIFOpenL(osLockFile, "wb");
1491 0 : if (!f)
1492 : {
1493 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot create lock file");
1494 0 : return false;
1495 : }
1496 0 : m_psLockFile = f;
1497 0 : CPLAcquireMutex(m_poRefreshLockFileMutex, 1000);
1498 0 : m_bExitRefreshLockFileThread = false;
1499 0 : m_bRefreshLockFileThreadStarted = false;
1500 0 : CPLReleaseMutex(m_poRefreshLockFileMutex);
1501 : // Config option mostly for testing purposes
1502 : // coverity[tainted_data]
1503 0 : m_dfRefreshLockDelay = CPLAtof(CPLGetConfigOption(
1504 : "OGR_SHAPE_LOCK_DELAY",
1505 : CPLSPrintf("%d", knREFRESH_LOCK_FILE_DELAY_SEC)));
1506 0 : m_hRefreshLockFileThread =
1507 0 : CPLCreateJoinableThread(OGRShapeDataSource::RefreshLockFile, this);
1508 0 : if (!m_hRefreshLockFileThread)
1509 : {
1510 0 : VSIFCloseL(m_psLockFile);
1511 0 : m_psLockFile = nullptr;
1512 0 : VSIUnlink(osLockFile);
1513 : }
1514 : else
1515 : {
1516 0 : CPLAcquireMutex(m_poRefreshLockFileMutex, 1000);
1517 0 : while (!m_bRefreshLockFileThreadStarted)
1518 : {
1519 0 : CPLCondWait(m_poRefreshLockFileCond, m_poRefreshLockFileMutex);
1520 : }
1521 0 : CPLReleaseMutex(m_poRefreshLockFileMutex);
1522 : }
1523 : }
1524 :
1525 12 : CPLString osVSIZipDirname(GetVSIZipPrefixeDir());
1526 6 : vsi_l_offset nTotalUncompressedSize = 0;
1527 12 : CPLStringList aosFiles(VSIReadDir(osVSIZipDirname));
1528 20 : for (int i = 0; i < aosFiles.size(); i++)
1529 : {
1530 14 : const char *pszFilename = aosFiles[i];
1531 14 : if (!EQUAL(pszFilename, ".") && !EQUAL(pszFilename, ".."))
1532 : {
1533 : const CPLString osSrcFile(
1534 28 : CPLFormFilenameSafe(osVSIZipDirname, pszFilename, nullptr));
1535 : VSIStatBufL sStat;
1536 14 : if (VSIStatL(osSrcFile, &sStat) == 0)
1537 : {
1538 14 : nTotalUncompressedSize += sStat.st_size;
1539 : }
1540 : }
1541 : }
1542 :
1543 12 : CPLString osTemporaryDir(GetDescription());
1544 6 : osTemporaryDir += "_tmp_uncompressed";
1545 :
1546 : const char *pszUseVsimem =
1547 6 : CPLGetConfigOption("OGR_SHAPE_USE_VSIMEM_FOR_TEMP", "AUTO");
1548 12 : if (EQUAL(pszUseVsimem, "YES") ||
1549 6 : (EQUAL(pszUseVsimem, "AUTO") && nTotalUncompressedSize > 0 &&
1550 : nTotalUncompressedSize <
1551 3 : static_cast<GUIntBig>(CPLGetUsablePhysicalRAM() / 10)))
1552 : {
1553 3 : osTemporaryDir = VSIMemGenerateHiddenFilename("shapedriver");
1554 : }
1555 6 : CPLDebug("Shape", "Uncompressing to %s", osTemporaryDir.c_str());
1556 :
1557 6 : VSIRmdirRecursive(osTemporaryDir);
1558 6 : if (VSIMkdir(osTemporaryDir, 0755) != 0)
1559 0 : return returnError();
1560 20 : for (int i = 0; i < aosFiles.size(); i++)
1561 : {
1562 14 : const char *pszFilename = aosFiles[i];
1563 14 : if (!EQUAL(pszFilename, ".") && !EQUAL(pszFilename, ".."))
1564 : {
1565 : const CPLString osSrcFile(
1566 14 : CPLFormFilenameSafe(osVSIZipDirname, pszFilename, nullptr));
1567 : const CPLString osDestFile(
1568 14 : CPLFormFilenameSafe(osTemporaryDir, pszFilename, nullptr));
1569 14 : if (CPLCopyFile(osDestFile, osSrcFile) != 0)
1570 : {
1571 0 : VSIRmdirRecursive(osTemporaryDir);
1572 0 : return returnError();
1573 : }
1574 : }
1575 : }
1576 :
1577 6 : m_osTemporaryUnzipDir = std::move(osTemporaryDir);
1578 :
1579 9 : for (auto &poLayer : m_apoLayers)
1580 : {
1581 3 : poLayer->UpdateFollowingDeOrRecompression();
1582 : }
1583 :
1584 6 : return true;
1585 : }
1586 :
1587 : /************************************************************************/
1588 : // RecompressIfNeeded() */
1589 : /************************************************************************/
1590 :
1591 3821 : bool OGRShapeDataSource::RecompressIfNeeded(
1592 : const std::vector<CPLString> &layerNames)
1593 : {
1594 3821 : if (eAccess != GA_Update || !m_bIsZip || m_osTemporaryUnzipDir.empty())
1595 3815 : return true;
1596 :
1597 0 : auto returnError = [this]()
1598 : {
1599 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot recompress %s",
1600 0 : GetDescription());
1601 0 : RemoveLockFile();
1602 0 : return false;
1603 6 : };
1604 :
1605 12 : CPLStringList aosFiles(VSIReadDir(m_osTemporaryUnzipDir));
1606 12 : CPLString osTmpZip(m_osTemporaryUnzipDir + ".zip");
1607 6 : VSIUnlink(osTmpZip);
1608 18 : CPLString osTmpZipWithVSIZip("/vsizip/{" + osTmpZip + '}');
1609 :
1610 12 : std::map<CPLString, int> oMapLayerOrder;
1611 12 : for (size_t i = 0; i < layerNames.size(); i++)
1612 6 : oMapLayerOrder[layerNames[i]] = static_cast<int>(i);
1613 :
1614 12 : std::vector<CPLString> sortedFiles;
1615 6 : vsi_l_offset nTotalUncompressedSize = 0;
1616 36 : for (int i = 0; i < aosFiles.size(); i++)
1617 : {
1618 30 : sortedFiles.emplace_back(aosFiles[i]);
1619 : const CPLString osSrcFile(
1620 60 : CPLFormFilenameSafe(m_osTemporaryUnzipDir, aosFiles[i], nullptr));
1621 : VSIStatBufL sStat;
1622 30 : if (VSIStatL(osSrcFile, &sStat) == 0)
1623 : {
1624 30 : nTotalUncompressedSize += sStat.st_size;
1625 : }
1626 : }
1627 :
1628 : // Sort files by their layer orders, and then for files of the same layer,
1629 : // make shp appear first, and then by filename order
1630 6 : std::sort(sortedFiles.begin(), sortedFiles.end(),
1631 208 : [&oMapLayerOrder](const CPLString &a, const CPLString &b)
1632 : {
1633 52 : int iA = INT_MAX;
1634 : auto oIterA =
1635 52 : oMapLayerOrder.find(CPLGetBasenameSafe(a).c_str());
1636 52 : if (oIterA != oMapLayerOrder.end())
1637 46 : iA = oIterA->second;
1638 52 : int iB = INT_MAX;
1639 : auto oIterB =
1640 52 : oMapLayerOrder.find(CPLGetBasenameSafe(b).c_str());
1641 52 : if (oIterB != oMapLayerOrder.end())
1642 36 : iB = oIterB->second;
1643 52 : if (iA < iB)
1644 14 : return true;
1645 38 : if (iA > iB)
1646 4 : return false;
1647 34 : if (iA != INT_MAX)
1648 : {
1649 32 : if (EQUAL(CPLGetExtensionSafe(a).c_str(), "shp"))
1650 5 : return true;
1651 27 : if (EQUAL(CPLGetExtensionSafe(b).c_str(), "shp"))
1652 11 : return false;
1653 : }
1654 18 : return a < b;
1655 : });
1656 :
1657 : CPLConfigOptionSetter oZIP64Setter(
1658 : "CPL_CREATE_ZIP64",
1659 12 : nTotalUncompressedSize < 4000U * 1000 * 1000 ? "NO" : "YES", true);
1660 :
1661 : /* Maintain a handle on the ZIP opened */
1662 6 : VSILFILE *fpZIP = VSIFOpenExL(osTmpZipWithVSIZip, "wb", true);
1663 6 : if (fpZIP == nullptr)
1664 : {
1665 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s: %s",
1666 : osTmpZipWithVSIZip.c_str(), VSIGetLastErrorMsg());
1667 0 : return returnError();
1668 : }
1669 :
1670 36 : for (const auto &osFilename : sortedFiles)
1671 : {
1672 30 : const char *pszFilename = osFilename.c_str();
1673 30 : if (!EQUAL(pszFilename, ".") && !EQUAL(pszFilename, ".."))
1674 : {
1675 26 : const CPLString osSrcFile(CPLFormFilenameSafe(
1676 26 : m_osTemporaryUnzipDir, pszFilename, nullptr));
1677 : const CPLString osDestFile(
1678 26 : CPLFormFilenameSafe(osTmpZipWithVSIZip, pszFilename, nullptr));
1679 26 : if (CPLCopyFile(osDestFile, osSrcFile) != 0)
1680 : {
1681 0 : VSIFCloseL(fpZIP);
1682 0 : return returnError();
1683 : }
1684 : }
1685 : }
1686 :
1687 6 : VSIFCloseL(fpZIP);
1688 :
1689 : const bool bOverwrite =
1690 6 : CPLTestBool(CPLGetConfigOption("OGR_SHAPE_PACK_IN_PLACE",
1691 : #ifdef _WIN32
1692 : "YES"
1693 : #else
1694 : "NO"
1695 : #endif
1696 : ));
1697 6 : if (bOverwrite)
1698 : {
1699 0 : VSILFILE *fpTarget = nullptr;
1700 0 : for (int i = 0; i < 10; i++)
1701 : {
1702 0 : fpTarget = VSIFOpenL(GetDescription(), "rb+");
1703 0 : if (fpTarget)
1704 0 : break;
1705 0 : CPLSleep(0.1);
1706 : }
1707 0 : if (!fpTarget)
1708 0 : return returnError();
1709 0 : bool bCopyOK = CopyInPlace(fpTarget, osTmpZip);
1710 0 : VSIFCloseL(fpTarget);
1711 0 : VSIUnlink(osTmpZip);
1712 0 : if (!bCopyOK)
1713 : {
1714 0 : return returnError();
1715 : }
1716 : }
1717 : else
1718 : {
1719 12 : if (VSIUnlink(GetDescription()) != 0 ||
1720 6 : CPLMoveFile(GetDescription(), osTmpZip) != 0)
1721 : {
1722 0 : return returnError();
1723 : }
1724 : }
1725 :
1726 6 : VSIRmdirRecursive(m_osTemporaryUnzipDir);
1727 6 : m_osTemporaryUnzipDir.clear();
1728 :
1729 6 : for (auto &poLayer : m_apoLayers)
1730 : {
1731 0 : poLayer->UpdateFollowingDeOrRecompression();
1732 : }
1733 :
1734 6 : RemoveLockFile();
1735 :
1736 6 : return true;
1737 : }
1738 :
1739 : /************************************************************************/
1740 : /* CopyInPlace() */
1741 : /************************************************************************/
1742 :
1743 3 : bool OGRShapeDataSource::CopyInPlace(VSILFILE *fpTarget,
1744 : const CPLString &osSourceFilename)
1745 : {
1746 3 : return CPL_TO_BOOL(VSIOverwriteFile(fpTarget, osSourceFilename.c_str()));
1747 : }
|