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