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