Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/shape/ogrshape.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Private definitions within the Shapefile driver to implement
5
 *           integration with OGR.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1999,  Les Technologies SoftMap Inc.
10
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#ifndef OGRSHAPE_H_INCLUDED
16
#define OGRSHAPE_H_INCLUDED
17
18
#ifdef RENAME_INTERNAL_SHAPELIB_SYMBOLS
19
#include "gdal_shapelib_symbol_rename.h"
20
#endif
21
22
#include "cpl_multiproc.h"
23
#include "ogrsf_frmts.h"
24
#include "shapefil.h"
25
#include "shp_vsi.h"
26
#include "ogrlayerpool.h"
27
#include <set>
28
#include <vector>
29
30
/* Was limited to 255 until OGR 1.10, but 254 seems to be a more */
31
/* conventional limit (http://en.wikipedia.org/wiki/Shapefile, */
32
/* http://www.clicketyclick.dk/databases/xbase/format/data_types.html, */
33
/* #5052 ) */
34
0
#define OGR_DBF_MAX_FIELD_WIDTH 254
35
36
/* ==================================================================== */
37
/*      Functions from Shape2ogr.cpp.                                   */
38
/* ==================================================================== */
39
OGRFeature *SHPReadOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
40
                              OGRFeatureDefn *poDefn, int iShape,
41
                              SHPObject *psShape, const char *pszSHPEncoding,
42
                              bool &bHasWarnedWrongWindingOrder);
43
std::unique_ptr<OGRGeometry>
44
SHPReadOGRObject(SHPHandle hSHP, int iShape, SHPObject *psShape,
45
                 bool &bHasWarnedWrongWindingOrder,
46
                 OGRwkbGeometryType eLayerGeomType);
47
OGRFeatureDefnRefCountedPtr
48
SHPReadOGRFeatureDefn(const char *pszName, SHPHandle hSHP, DBFHandle hDBF,
49
                      VSILFILE *fpSHPXML, const char *pszSHPEncoding,
50
                      int bAdjustType);
51
OGRErr SHPWriteOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
52
                          OGRFeatureDefn *m_poFeatureDefn,
53
                          OGRFeature *poFeature, const char *pszSHPEncoding,
54
                          bool *pbTruncationWarningEmitted, bool bRewind);
55
56
/************************************************************************/
57
/*                        OGRShapeGeomFieldDefn                         */
58
/************************************************************************/
59
60
class OGRShapeGeomFieldDefn final : public OGRGeomFieldDefn
61
{
62
    CPL_DISALLOW_COPY_ASSIGN(OGRShapeGeomFieldDefn)
63
64
    std::string m_osFullName{};
65
    mutable bool m_bSRSSet = false;
66
    mutable CPLString m_osPrjFile{};
67
68
  public:
69
    OGRShapeGeomFieldDefn(const char *pszFullNameIn, OGRwkbGeometryType eType,
70
                          int bSRSSetIn, const OGRSpatialReference *poSRSIn)
71
0
        : OGRGeomFieldDefn("", eType), m_osFullName(pszFullNameIn),
72
0
          m_bSRSSet(CPL_TO_BOOL(bSRSSetIn))
73
0
    {
74
0
        SetSpatialRef(poSRSIn);
75
0
    }
76
77
    const OGRSpatialReference *GetSpatialRef() const override;
78
79
    void SetSRSSet()
80
0
    {
81
0
        m_bSRSSet = true;
82
0
    }
83
84
    const CPLString &GetPrjFilename() const
85
0
    {
86
0
        return m_osPrjFile;
87
0
    }
88
89
    void SetPrjFilename(const std::string &osFilename)
90
0
    {
91
0
        m_osPrjFile = osFilename;
92
0
    }
93
};
94
95
/************************************************************************/
96
/*                            OGRShapeLayer                             */
97
/************************************************************************/
98
99
class OGRShapeDataSource;
100
101
class OGRShapeLayer final : public OGRAbstractProxiedLayer
102
{
103
    CPL_DISALLOW_COPY_ASSIGN(OGRShapeLayer)
104
105
    OGRShapeDataSource *m_poDS = nullptr;
106
107
    OGRFeatureDefnRefCountedPtr m_poFeatureDefn{};
108
    int m_iNextShapeId = 0;
109
    int m_nTotalShapeCount = 0;
110
111
    std::string m_osFullName{};
112
113
    SHPHandle m_hSHP = nullptr;
114
    DBFHandle m_hDBF = nullptr;
115
116
    bool m_bUpdateAccess = false;
117
    bool m_bHasShpXML = false;
118
119
    OGRwkbGeometryType m_eRequestedGeomType = wkbUnknown;
120
    int ResetGeomType(int nNewType);
121
122
    bool ScanIndices();
123
124
    GIntBig *m_panMatchingFIDs = nullptr;
125
    int m_iMatchingFID = 0;
126
    void ClearMatchingFIDs();
127
128
    OGRGeometry *m_poFilterGeomLastValid = nullptr;
129
    int m_nSpatialFIDCount = 0;
130
    int *m_panSpatialFIDs = nullptr;
131
    void ClearSpatialFIDs();
132
133
    bool m_bHeaderDirty = false;
134
    bool m_bSHPNeedsRepack = false;
135
    bool m_bCheckedForQIX = false;
136
    SHPTreeDiskHandle m_hQIX = nullptr;
137
    bool CheckForQIX();
138
139
    bool m_bCheckedForSBN = false;
140
    SBNSearchHandle m_hSBN = nullptr;
141
    bool CheckForSBN();
142
143
    bool m_bSbnSbxDeleted = false;
144
145
    CPLString ConvertCodePage(const char *);
146
    CPLString m_osEncoding{};
147
148
    bool m_bTruncationWarningEmitted = false;
149
150
    bool m_bHSHPWasNonNULL = false;  // Must try to reopen a .shp?
151
    bool m_bHDBFWasNonNULL = false;  // Must try to reopen a .dbf
152
153
    // Current state of opening of file descriptor to .shp and .dbf.
154
155
    typedef enum
156
    {
157
        FD_OPENED,
158
        FD_CLOSED,
159
        FD_CANNOT_REOPEN
160
    } FileDescriptorState;
161
162
    FileDescriptorState m_eFileDescriptorsState = FD_OPENED;
163
164
    bool TouchLayer();
165
    bool ReopenFileDescriptors();
166
167
    bool m_bResizeAtClose = false;
168
169
    void TruncateDBF();
170
171
    bool m_bCreateSpatialIndexAtClose = false;
172
    bool m_bRewindOnWrite = false;
173
    bool m_bHasWarnedWrongWindingOrder = false;
174
    bool m_bLastGetNextArrowArrayUsedOptimizedCodePath = false;
175
176
    bool m_bAutoRepack = false;
177
178
    typedef enum
179
    {
180
        YES,
181
        NO,
182
        MAYBE
183
    } NormandyState; /* French joke. "Peut'et' ben que oui, peut'et' ben que
184
                        non." Sorry :-) */
185
186
    NormandyState m_eNeedRepack = MAYBE;
187
188
    // Set of field names (in upper case). Built and invalidated when convenient
189
    std::set<CPLString> m_oSetUCFieldName{};
190
191
    bool StartUpdate(const char *pszOperation);
192
193
    void CloseUnderlyingLayer() override;
194
195
    // WARNING: Each of the below public methods should start with a call to
196
    // TouchLayer() and test its return value, so as to make sure that
197
    // the layer is properly re-opened if necessary.
198
199
  public:
200
    OGRErr CreateSpatialIndex(int nMaxDepth);
201
    OGRErr DropSpatialIndex();
202
    OGRErr Repack();
203
    OGRErr RecomputeExtent();
204
    OGRErr ResizeDBF();
205
206
    void SetResizeAtClose(bool bFlag)
207
0
    {
208
0
        m_bResizeAtClose = bFlag;
209
0
    }
210
211
    const char *GetFullName()
212
0
    {
213
0
        return m_osFullName.c_str();
214
0
    }
215
216
    void UpdateFollowingDeOrRecompression();
217
218
    OGRFeature *FetchShape(int iShapeId);
219
    int GetFeatureCountWithSpatialFilterOnly();
220
221
    OGRShapeLayer(OGRShapeDataSource *poDSIn, const char *pszName,
222
                  SHPHandle hSHP, DBFHandle hDBF,
223
                  const OGRSpatialReference *poSRS, bool bSRSSet,
224
                  const std::string &osPrjFilename, bool bUpdate,
225
                  OGRwkbGeometryType eReqType, bool bCreateLayer);
226
    ~OGRShapeLayer() override;
227
228
    GDALDataset *GetDataset() override;
229
230
    void ResetReading() override;
231
    OGRFeature *GetNextFeature() override;
232
    OGRErr SetNextByIndex(GIntBig nIndex) override;
233
234
    int GetNextArrowArray(struct ArrowArrayStream *,
235
                          struct ArrowArray *out_array) override;
236
    const char *GetMetadataItem(const char *pszName,
237
                                const char *pszDomain) override;
238
239
    OGRFeature *GetFeature(GIntBig nFeatureId) override;
240
    OGRErr ISetFeature(OGRFeature *poFeature) override;
241
    OGRErr DeleteFeature(GIntBig nFID) override;
242
    OGRErr ICreateFeature(OGRFeature *poFeature) override;
243
    OGRErr SyncToDisk() override;
244
245
    using OGRAbstractProxiedLayer::GetLayerDefn;
246
247
    const OGRFeatureDefn *GetLayerDefn() const override
248
0
    {
249
0
        return m_poFeatureDefn.get();
250
0
    }
251
252
    GIntBig GetFeatureCount(int) override;
253
    OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
254
                      bool bForce) override;
255
256
    OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
257
                        bool bForce) override;
258
259
    OGRErr CreateField(const OGRFieldDefn *poField,
260
                       int bApproxOK = TRUE) override;
261
    OGRErr DeleteField(int iField) override;
262
    OGRErr ReorderFields(int *panMap) override;
263
    OGRErr AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
264
                          int nFlags) override;
265
    OGRErr AlterGeomFieldDefn(int iGeomField,
266
                              const OGRGeomFieldDefn *poNewGeomFieldDefn,
267
                              int nFlagsIn) override;
268
269
    int TestCapability(const char *) const override;
270
271
    OGRErr ISetSpatialFilter(int iGeomField,
272
                             const OGRGeometry *poGeom) override;
273
274
    OGRErr SetAttributeFilter(const char *) override;
275
276
    OGRErr Rename(const char *pszNewName) override;
277
278
    void AddToFileList(CPLStringList &oFileList);
279
280
    void CreateSpatialIndexAtClose(int bFlag)
281
0
    {
282
0
        m_bCreateSpatialIndexAtClose = CPL_TO_BOOL(bFlag);
283
0
    }
284
285
    void SetModificationDate(const char *pszStr);
286
287
    void SetAutoRepack(bool b)
288
0
    {
289
0
        m_bAutoRepack = b;
290
0
    }
291
292
    void SetWriteDBFEOFChar(bool b);
293
};
294
295
/************************************************************************/
296
/*                          OGRShapeDataSource                          */
297
/************************************************************************/
298
299
class OGRShapeDataSource final : public GDALDataset
300
{
301
    std::vector<std::unique_ptr<OGRShapeLayer>> m_apoLayers{};
302
    bool m_bSingleFileDataSource = false;
303
    std::unique_ptr<OGRLayerPool> m_poPool{};
304
305
    mutable std::vector<CPLString> m_oVectorLayerName{};
306
307
    bool m_b2GBLimit = false;
308
    bool m_bIsZip = false;
309
    bool m_bSingleLayerZip = false;
310
    CPLString m_osTemporaryUnzipDir{};
311
    CPLMutex *m_poRefreshLockFileMutex = nullptr;
312
    CPLCond *m_poRefreshLockFileCond = nullptr;
313
    VSILFILE *m_psLockFile = nullptr;
314
    CPLJoinableThread *m_hRefreshLockFileThread = nullptr;
315
    bool m_bExitRefreshLockFileThread = false;
316
    bool m_bRefreshLockFileThreadStarted = false;
317
    double m_dfRefreshLockDelay = 0;
318
319
    std::vector<CPLString> GetLayerNames() const;
320
    void AddLayer(std::unique_ptr<OGRShapeLayer> poLayer);
321
    static void RefreshLockFile(void *_self);
322
    void RemoveLockFile();
323
    bool RecompressIfNeeded(const std::vector<CPLString> &layerNames);
324
325
    CPL_DISALLOW_COPY_ASSIGN(OGRShapeDataSource)
326
327
  public:
328
    OGRShapeDataSource();
329
    ~OGRShapeDataSource() override;
330
331
    CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
332
333
    OGRLayerPool *GetPool() const
334
0
    {
335
0
        return m_poPool.get();
336
0
    }
337
338
    bool Open(GDALOpenInfo *poOpenInfo, bool bTestOpen,
339
              bool bForceSingleFileDataSource = false);
340
    bool OpenFile(const char *, bool bUpdate);
341
    bool OpenZip(GDALOpenInfo *poOpenInfo, const char *pszOriFilename);
342
    bool CreateZip(const char *pszOriFilename);
343
344
    int GetLayerCount() const override;
345
    const OGRLayer *GetLayer(int) const override;
346
    OGRLayer *GetLayerByName(const char *) override;
347
348
    OGRLayer *ICreateLayer(const char *pszName,
349
                           const OGRGeomFieldDefn *poGeomFieldDefn,
350
                           CSLConstList papszOptions) override;
351
352
    OGRLayer *ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
353
                         const char *pszDialect) override;
354
355
    int TestCapability(const char *) const override;
356
    OGRErr DeleteLayer(int iLayer) override;
357
358
    char **GetFileList() override;
359
360
    void SetLastUsedLayer(OGRShapeLayer *poLayer);
361
    void UnchainLayer(OGRShapeLayer *poLayer);
362
363
    bool UncompressIfNeeded();
364
365
    SHPHandle DS_SHPOpen(const char *pszShapeFile, const char *pszAccess);
366
    DBFHandle DS_DBFOpen(const char *pszDBFFile, const char *pszAccess);
367
368
    char **GetOpenOptions()
369
0
    {
370
0
        return papszOpenOptions;
371
0
    }
372
373
    static const char *const *GetExtensionsForDeletion();
374
375
    bool IsZip() const
376
0
    {
377
0
        return m_bIsZip;
378
0
    }
379
380
    CPLString GetVSIZipPrefixeDir() const
381
0
    {
382
0
        return CPLString("/vsizip/{").append(GetDescription()).append("}");
383
0
    }
384
385
    const CPLString &GetTemporaryUnzipDir() const
386
0
    {
387
0
        return m_osTemporaryUnzipDir;
388
0
    }
389
390
    static bool CopyInPlace(VSILFILE *fpTarget,
391
                            const CPLString &osSourceFilename);
392
};
393
394
#endif /* ndef OGRSHAPE_H_INCLUDED */