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