Coverage Report

Created: 2026-05-16 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/openfilegdb/ogr_openfilegdb.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements Open FileGDB OGR driver.
5
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#ifndef OGR_OPENFILEGDB_H_INCLUDED
14
#define OGR_OPENFILEGDB_H_INCLUDED
15
16
#include "ogrsf_frmts.h"
17
#include "filegdbtable.h"
18
#include "ogr_swq.h"
19
#include "cpl_mem_cache.h"
20
#include "cpl_quad_tree.h"
21
22
#include "gdal_rat.h"
23
24
#include <array>
25
#include <cmath>
26
#include <vector>
27
#include <map>
28
29
using namespace OpenFileGDB;
30
31
std::string OFGDBGenerateUUID(bool bInit = false);
32
33
int OGROpenFileGDBIsComparisonOp(int op);
34
35
// The FileGeodatabase format does not really allow strings of arbitrary width
36
// in the XML and .gdbtable header declaration. They must have a non-zero
37
// maximum width. But if we put it to a huge value (let's say 1 billion), this
38
// causes crashes in some Esri products (cf #5952, perhaps they allocate
39
// std::string's to that maximum size?).
40
// Hence this default of a relative large but not too large
41
// width when creating a OGR string field width of unspecified width.
42
// Note that when opening a FileGeodatabase with string fields of that width,
43
// we do not advertise it in OGRFieldDefn::GetWidth() but we advertise 0 instead,
44
// to allow round-tripping.
45
constexpr int DEFAULT_STRING_WIDTH = 65536;
46
47
// UUID of object type
48
constexpr const char *pszFolderTypeUUID =
49
    "{f3783e6f-65ca-4514-8315-ce3985dad3b1}";
50
constexpr const char *pszWorkspaceTypeUUID =
51
    "{c673fe0f-7280-404f-8532-20755dd8fc06}";
52
constexpr const char *pszFeatureDatasetTypeUUID =
53
    "{74737149-DCB5-4257-8904-B9724E32A530}";
54
constexpr const char *pszFeatureClassTypeUUID =
55
    "{70737809-852c-4a03-9e22-2cecea5b9bfa}";
56
constexpr const char *pszTableTypeUUID =
57
    "{cd06bc3b-789d-4c51-aafa-a467912b8965}";
58
constexpr const char *pszRangeDomainTypeUUID =
59
    "{c29da988-8c3e-45f7-8b5c-18e51ee7beb4}";
60
constexpr const char *pszCodedDomainTypeUUID =
61
    "{8c368b12-a12e-4c7e-9638-c9c64e69e98f}";
62
constexpr const char *pszRelationshipTypeUUID =
63
    "{b606a7e1-fa5b-439c-849c-6e9c2481537b}";
64
65
// UUID of relationship type
66
constexpr const char *pszDatasetInFeatureDatasetUUID =
67
    "{a1633a59-46ba-4448-8706-d8abe2b2b02e}";
68
constexpr const char *pszDatasetInFolderUUID =
69
    "{dc78f1ab-34e4-43ac-ba47-1c4eabd0e7c7}";
70
constexpr const char *pszDomainInDatasetUUID =
71
    "{17e08adb-2b31-4dcd-8fdd-df529e88f843}";
72
constexpr const char *pszDatasetsRelatedThroughUUID =
73
    "{725badab-3452-491b-a795-55f32d67229c}";
74
75
/************************************************************************/
76
/*                          FETCH_FIELD_IDX()                           */
77
/************************************************************************/
78
79
#define FETCH_FIELD_IDX_WITH_RET(idxName, varName, type, errorCode)            \
80
127k
    const int idxName = oTable.GetFieldIdx(varName);                           \
81
127k
    if (idxName < 0 || oTable.GetField(idxName)->GetType() != type)            \
82
127k
    {                                                                          \
83
0
        CPLError(CE_Failure, CPLE_AppDefined,                                  \
84
0
                 "Could not find field %s in table %s", varName,               \
85
0
                 oTable.GetFilename().c_str());                                \
86
0
        return errorCode;                                                      \
87
0
    }
88
89
#define FETCH_FIELD_IDX(idxName, varName, type)                                \
90
127k
    FETCH_FIELD_IDX_WITH_RET(idxName, varName, type, false)
91
92
/************************************************************************/
93
/*                         OGROpenFileGDBLayer                          */
94
/************************************************************************/
95
96
class OGROpenFileGDBDataSource;
97
class OGROpenFileGDBGeomFieldDefn;
98
class OGROpenFileGDBFeatureDefn;
99
100
typedef enum
101
{
102
    SPI_IN_BUILDING,
103
    SPI_COMPLETED,
104
    SPI_INVALID,
105
} SPIState;
106
107
class OGROpenFileGDBLayer final : public OGRLayer
108
{
109
    friend class OGROpenFileGDBGeomFieldDefn;
110
    friend class OGROpenFileGDBFeatureDefn;
111
112
    OGROpenFileGDBDataSource *m_poDS = nullptr;
113
    CPLString m_osGDBFilename{};
114
    CPLString m_osName{};
115
    std::string m_osPath{};
116
    std::string m_osThisGUID{};
117
    bool m_bEditable = false;
118
    bool m_bRegisteredTable = true;
119
    CPLStringList m_aosCreationOptions{};
120
    FileGDBTable *m_poLyrTable = nullptr;
121
    OGROpenFileGDBFeatureDefn *m_poFeatureDefn = nullptr;
122
    int m_iGeomFieldIdx = -1;
123
    int m_iAreaField = -1;    // index of Shape_Area field
124
    int m_iLengthField = -1;  // index of Shape_Length field
125
    int64_t m_iCurFeat = 0;
126
    int m_iFIDAsRegularColumnIndex = -1;
127
    std::string m_osDefinition{};
128
    std::string m_osDocumentation{};
129
    std::string m_osConfigurationKeyword{};
130
    OGRwkbGeometryType m_eGeomType = wkbNone;
131
    bool m_bArcGISPro32OrLater = false;
132
    int m_bValidLayerDefn = -1;
133
    int m_bEOF = false;
134
    bool m_bTimeInUTC = false;
135
    std::string m_osFeatureDatasetGUID{};
136
137
    bool m_bWarnedDateNotConvertibleUTC = false;
138
139
    bool m_bHasCreatedBackupForTransaction = false;
140
    std::unique_ptr<OGRFeatureDefn> m_poFeatureDefnBackup{};
141
142
    int BuildLayerDefinition();
143
    int BuildGeometryColumnGDBv10(const std::string &osParentDefinition);
144
    OGRFeature *GetCurrentFeature();
145
146
    std::unique_ptr<FileGDBOGRGeometryConverter> m_poGeomConverter{};
147
148
    int m_iFieldToReadAsBinary = -1;
149
150
    FileGDBIterator *m_poAttributeIterator = nullptr;
151
    int m_bIteratorSufficientToEvaluateFilter = FALSE;
152
    FileGDBIterator *BuildIteratorFromExprNode(swq_expr_node *poNode);
153
154
    FileGDBIterator *m_poIterMinMax = nullptr;
155
156
    FileGDBSpatialIndexIterator *m_poSpatialIndexIterator = nullptr;
157
    FileGDBIterator *m_poCombinedIterator = nullptr;
158
159
    // Legacy behavior prior to handling of .spx file
160
    // To remove ultimately.
161
    SPIState m_eSpatialIndexState = SPI_IN_BUILDING;
162
    CPLQuadTree *m_pQuadTree = nullptr;
163
    void **m_pahFilteredFeatures = nullptr;
164
    int m_nFilteredFeatureCount = -1;
165
    static void GetBoundsFuncEx(const void *hFeature, CPLRectObj *pBounds,
166
                                void *pQTUserData);
167
168
    void TryToDetectMultiPatchKind();
169
    void BuildCombinedIterator();
170
    bool RegisterTable();
171
    void RefreshXMLDefinitionInMemory();
172
    bool CreateFeatureDataset(const char *pszFeatureDataset);
173
    std::string GetLaunderedFieldName(const std::string &osNameOri) const;
174
    std::string GetLaunderedLayerName(const std::string &osNameOri) const;
175
176
    mutable std::vector<std::string> m_aosTempStrings{};
177
    bool PrepareFileGDBFeature(OGRFeature *poFeature,
178
                               std::vector<OGRField> &fields,
179
                               const OGRGeometry *&poGeom, bool bUpdate);
180
181
    CPL_DISALLOW_COPY_ASSIGN(OGROpenFileGDBLayer)
182
183
  public:
184
    OGROpenFileGDBLayer(OGROpenFileGDBDataSource *poDS,
185
                        const char *pszGDBFilename, const char *pszName,
186
                        const std::string &osDefinition,
187
                        const std::string &osDocumentation, bool bEditable,
188
                        OGRwkbGeometryType eGeomType = wkbUnknown,
189
                        const std::string &osParentDefinition = std::string());
190
191
    OGROpenFileGDBLayer(OGROpenFileGDBDataSource *poDS,
192
                        const char *pszGDBFilename, const char *pszName,
193
                        OGRwkbGeometryType eType, CSLConstList papszOptions);
194
195
    ~OGROpenFileGDBLayer() override;
196
197
    bool Create(const OGRGeomFieldDefn *poSrcGeomFieldDefn);
198
    void Close();
199
200
    const std::string &GetFilename() const
201
0
    {
202
0
        return m_osGDBFilename;
203
0
    }
204
205
    const std::string &GetXMLDefinition()
206
0
    {
207
0
        return m_osDefinition;
208
0
    }
209
210
    const std::string &GetXMLDocumentation()
211
0
    {
212
0
        return m_osDocumentation;
213
0
    }
214
215
    int GetAttrIndexUse()
216
0
    {
217
0
        return (m_poAttributeIterator == nullptr)        ? 0
218
0
               : (m_bIteratorSufficientToEvaluateFilter) ? 2
219
0
                                                         : 1;
220
0
    }
221
222
    const OGRField *GetMinMaxValue(const OGRFieldDefn *poFieldDefn, int bIsMin,
223
                                   int &eOutType);
224
    int GetMinMaxSumCount(const OGRFieldDefn *poFieldDefn, double &dfMin,
225
                          double &dfMax, double &dfSum, int &nCount);
226
    bool HasIndexForField(const char *pszFieldName);
227
    FileGDBIterator *BuildIndex(const char *pszFieldName, int bAscending,
228
                                int op, swq_expr_node *poValue);
229
230
    SPIState GetSpatialIndexState() const
231
0
    {
232
0
        return m_eSpatialIndexState;
233
0
    }
234
235
    int IsValidLayerDefn()
236
0
    {
237
0
        return BuildLayerDefinition();
238
0
    }
239
240
    void CreateSpatialIndex();
241
    void CreateIndex(const std::string &osIdxName,
242
                     const std::string &osExpression);
243
    bool Repack(GDALProgressFunc pfnProgress, void *pProgressData);
244
    void RecomputeExtent();
245
246
    bool CheckFreeListConsistency();
247
248
    bool BeginEmulatedTransaction();
249
    bool CommitEmulatedTransaction();
250
    bool RollbackEmulatedTransaction();
251
252
    GDALDataset *GetDataset() override;
253
254
    const char *GetName() const override
255
656k
    {
256
656k
        return m_osName.c_str();
257
656k
    }
258
259
    OGRwkbGeometryType GetGeomType() const override;
260
261
    const char *GetFIDColumn() const override;
262
263
    void ResetReading() override;
264
    OGRFeature *GetNextFeature() override;
265
    OGRFeature *GetFeature(GIntBig nFeatureId) override;
266
    OGRErr SetNextByIndex(GIntBig nIndex) override;
267
268
    GIntBig GetFeatureCount(int bForce = TRUE) override;
269
    OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
270
                      bool bForce) override;
271
272
    OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent,
273
                        bool bForce) override;
274
275
    const OGRFeatureDefn *GetLayerDefn() const override;
276
277
    virtual OGRErr ISetSpatialFilter(int iGeomField,
278
                                     const OGRGeometry *poGeom) override;
279
280
    OGRErr SetAttributeFilter(const char *pszFilter) override;
281
282
    int TestCapability(const char *) const override;
283
284
    OGRErr Rename(const char *pszNewName) override;
285
286
    virtual OGRErr CreateField(const OGRFieldDefn *poField,
287
                               int bApproxOK) override;
288
    OGRErr DeleteField(int iFieldToDelete) override;
289
    virtual OGRErr AlterFieldDefn(int iFieldToAlter,
290
                                  OGRFieldDefn *poNewFieldDefn,
291
                                  int nFlags) override;
292
    virtual OGRErr
293
    AlterGeomFieldDefn(int iGeomFieldToAlter,
294
                       const OGRGeomFieldDefn *poNewGeomFieldDefn,
295
                       int nFlagsIn) override;
296
297
    OGRErr ICreateFeature(OGRFeature *poFeature) override;
298
    OGRErr ISetFeature(OGRFeature *poFeature) override;
299
    OGRErr DeleteFeature(GIntBig nFID) override;
300
301
    OGRErr SyncToDisk() override;
302
};
303
304
/************************************************************************/
305
/*                     OGROpenFileGDBGeomFieldDefn                      */
306
/************************************************************************/
307
class OGROpenFileGDBGeomFieldDefn final : public OGRGeomFieldDefn
308
{
309
    OGROpenFileGDBLayer *m_poLayer;
310
311
    CPL_DISALLOW_COPY_ASSIGN(OGROpenFileGDBGeomFieldDefn)
312
313
  public:
314
    OGROpenFileGDBGeomFieldDefn(OGROpenFileGDBLayer *poLayer,
315
                                const char *pszNameIn,
316
                                OGRwkbGeometryType eGeomTypeIn)
317
13.0k
        : OGRGeomFieldDefn(pszNameIn, eGeomTypeIn), m_poLayer(poLayer)
318
13.0k
    {
319
13.0k
    }
320
321
    ~OGROpenFileGDBGeomFieldDefn() override;
322
323
    void UnsetLayer()
324
13.0k
    {
325
13.0k
        m_poLayer = nullptr;
326
13.0k
    }
327
328
    const OGRSpatialReference *GetSpatialRef() const override
329
141k
    {
330
141k
        if (poSRS)
331
25.4k
            return poSRS.get();
332
116k
        if (m_poLayer != nullptr)
333
20.5k
            (void)m_poLayer->BuildLayerDefinition();
334
116k
        return poSRS.get();
335
141k
    }
336
};
337
338
/************************************************************************/
339
/*                      OGROpenFileGDBFeatureDefn                       */
340
/************************************************************************/
341
class OGROpenFileGDBFeatureDefn final : public OGRFeatureDefn
342
{
343
    OGROpenFileGDBLayer *m_poLayer;
344
    mutable bool m_bHasBuiltFieldDefn;
345
346
    void LazyGeomInit() const
347
5.29M
    {
348
        /* FileGDB v9 case */
349
5.29M
        if (!m_bHasBuiltFieldDefn && m_poLayer != nullptr &&
350
84.6k
            m_poLayer->m_eGeomType != wkbNone &&
351
37.5k
            m_poLayer->m_osDefinition.empty())
352
10.5k
        {
353
10.5k
            m_bHasBuiltFieldDefn = true;
354
10.5k
            (void)m_poLayer->BuildLayerDefinition();
355
10.5k
        }
356
5.29M
    }
357
358
    CPL_DISALLOW_COPY_ASSIGN(OGROpenFileGDBFeatureDefn)
359
360
  public:
361
    OGROpenFileGDBFeatureDefn(OGROpenFileGDBLayer *poLayer, const char *pszName,
362
                              bool bHasBuiltFieldDefn)
363
27.7k
        : OGRFeatureDefn(pszName), m_poLayer(poLayer),
364
27.7k
          m_bHasBuiltFieldDefn(bHasBuiltFieldDefn)
365
27.7k
    {
366
27.7k
    }
367
368
    ~OGROpenFileGDBFeatureDefn() override;
369
370
    void UnsetLayer()
371
27.7k
    {
372
27.7k
        if (!apoGeomFieldDefn.empty())
373
13.0k
            cpl::down_cast<OGROpenFileGDBGeomFieldDefn *>(
374
13.0k
                apoGeomFieldDefn[0].get())
375
13.0k
                ->UnsetLayer();
376
27.7k
        m_poLayer = nullptr;
377
27.7k
    }
378
379
    int GetFieldCount() const override
380
133M
    {
381
133M
        if (!m_bHasBuiltFieldDefn && m_poLayer != nullptr)
382
42.9k
        {
383
42.9k
            m_bHasBuiltFieldDefn = false;
384
42.9k
            (void)m_poLayer->BuildLayerDefinition();
385
42.9k
        }
386
133M
        return OGRFeatureDefn::GetFieldCount();
387
133M
    }
388
389
    int GetGeomFieldCount() const override
390
4.65M
    {
391
4.65M
        LazyGeomInit();
392
4.65M
        return OGRFeatureDefn::GetGeomFieldCount();
393
4.65M
    }
394
395
    OGRGeomFieldDefn *GetGeomFieldDefn(int i) override
396
324k
    {
397
324k
        LazyGeomInit();
398
324k
        return OGRFeatureDefn::GetGeomFieldDefn(i);
399
324k
    }
400
401
    const OGRGeomFieldDefn *GetGeomFieldDefn(int i) const override
402
314k
    {
403
314k
        LazyGeomInit();
404
314k
        return OGRFeatureDefn::GetGeomFieldDefn(i);
405
314k
    }
406
};
407
408
/************************************************************************/
409
/*                       OGROpenFileGDBDataSource                       */
410
/************************************************************************/
411
412
class OGROpenFileGDBDataSource final : public GDALDataset
413
{
414
    friend class OGROpenFileGDBLayer;
415
    friend class GDALOpenFileGDBRasterBand;
416
    friend class GDALOpenFileGDBRasterAttributeTable;
417
418
    CPLString m_osDirName{};
419
    std::vector<std::unique_ptr<OGROpenFileGDBLayer>> m_apoLayers{};
420
    std::vector<std::unique_ptr<OGROpenFileGDBLayer>> m_apoHiddenLayers{};
421
    char **m_papszFiles = nullptr;
422
    std::map<std::string, int> m_osMapNameToIdx{};
423
    std::shared_ptr<GDALGroup> m_poRootGroup{};
424
    CPLStringList m_aosSubdatasets{};
425
426
    std::string m_osRasterLayerName{};
427
    std::map<int, int> m_oMapGDALBandToGDBBandId{};
428
    bool m_bHasGeoTransform = false;
429
    GDALGeoTransform m_gt{};
430
    int m_nShiftBlockX =
431
        0;  // Offset to add to FileGDB col_nbr field to convert from GDAL block numbering to FileGDB one
432
    int m_nShiftBlockY =
433
        0;  // Offset to add to FileGDB row_nbr field to convert from GDAL block numbering to FileGDB one
434
    OGRSpatialReference m_oRasterSRS{};
435
    std::unique_ptr<OGRLayer> m_poBlkLayer{};
436
    enum class Compression
437
    {
438
        NONE,
439
        LZ77,
440
        JPEG,
441
        JPEG2000,
442
    };
443
    Compression m_eRasterCompression = Compression::NONE;
444
445
    lru11::Cache<std::string, OGRSpatialReferenceRefCountedPtr>
446
        m_oCacheWKTToSRS{};
447
448
    std::string m_osRootGUID{};
449
    std::string m_osGDBSystemCatalogFilename{};
450
    std::string m_osGDBSpatialRefsFilename{};
451
    std::string m_osGDBItemsFilename{};
452
    std::string m_osGDBItemRelationshipsFilename{};
453
    std::map<std::string, std::unique_ptr<GDALRelationship>>
454
        m_osMapRelationships{};
455
456
    // Related to transactions
457
    bool m_bInTransaction = false;
458
    bool m_bSystemTablesBackedup = false;
459
    std::string m_osTransactionBackupDirname{};
460
    std::set<OGROpenFileGDBLayer *>
461
        m_oSetLayersCreatedInTransaction{};  // must be vector of raw pointer
462
    std::set<std::unique_ptr<OGROpenFileGDBLayer>>
463
        m_oSetLayersDeletedInTransaction{};
464
465
    /* For debugging/testing */
466
    bool bLastSQLUsedOptimizedImplementation;
467
468
    bool OpenFileGDBv10(int iGDBItems, int nInterestTable,
469
                        const GDALOpenInfo *poOpenInfo,
470
                        const std::string &osRasterLayerName,
471
                        std::set<int> &oSetIgnoredRasterLayerTableNum,
472
                        bool &bRetryFileGDBOut);
473
    int OpenFileGDBv9(int iGDBFeatureClasses, int iGDBObjectClasses,
474
                      int nInterestTable, const GDALOpenInfo *poOpenInfo,
475
                      const std::string &osRasterLayerName,
476
                      std::set<int> &oSetIgnoredRasterLayerTableNum);
477
    bool OpenRaster(const GDALOpenInfo *poOpenInfo,
478
                    const std::string &osLayerName,
479
                    const std::string &osDefinition,
480
                    const std::string &osDocumentation);
481
    void GuessJPEGQuality(int nOverviewCount);
482
    void ReadAuxTable(const std::string &osLayerName);
483
484
    int FileExists(const char *pszFilename);
485
    std::unique_ptr<OGROpenFileGDBLayer>
486
    BuildLayerFromName(const char *pszName);
487
    OGRLayer *AddLayer(const CPLString &osName, int nInterestTable,
488
                       int &nCandidateLayers, int &nLayersCDF,
489
                       const CPLString &osDefinition,
490
                       const CPLString &osDocumentation,
491
                       OGRwkbGeometryType eGeomType,
492
                       const std::string &osParentDefinition);
493
494
    static bool IsPrivateLayerName(const CPLString &osName);
495
496
    bool CreateGDBSystemCatalog();
497
    bool CreateGDBDBTune();
498
    bool CreateGDBSpatialRefs();
499
    bool CreateGDBItems();
500
    bool CreateGDBItemTypes();
501
    bool CreateGDBItemRelationships();
502
    bool CreateGDBItemRelationshipTypes();
503
504
    bool BackupSystemTablesForTransaction();
505
506
    CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
507
508
    CPL_DISALLOW_COPY_ASSIGN(OGROpenFileGDBDataSource)
509
510
  public:
511
    OGROpenFileGDBDataSource();
512
    ~OGROpenFileGDBDataSource() override;
513
514
    bool Open(const GDALOpenInfo *poOpenInfo, bool &bRetryFileGDBOut);
515
    bool Create(const char *pszName);
516
517
    CPLErr FlushCache(bool bAtClosing = false) override;
518
519
    std::vector<std::unique_ptr<OGROpenFileGDBLayer>> &GetLayers()
520
0
    {
521
0
        return m_apoLayers;
522
0
    }
523
524
    int GetLayerCount() const override
525
424k
    {
526
424k
        return static_cast<int>(m_apoLayers.size());
527
424k
    }
528
529
    const OGRLayer *GetLayer(int) const override;
530
    OGROpenFileGDBLayer *GetLayerByName(const char *pszName) override;
531
    bool IsLayerPrivate(int) const override;
532
533
    OGRLayer *ExecuteSQL(const char *pszSQLCommand,
534
                         OGRGeometry *poSpatialFilter,
535
                         const char *pszDialect) override;
536
    void ReleaseResultSet(OGRLayer *poResultsSet) override;
537
538
    int TestCapability(const char *) const override;
539
540
    OGRLayer *ICreateLayer(const char *pszName,
541
                           const OGRGeomFieldDefn *poGeomFieldDefn,
542
                           CSLConstList papszOptions) override;
543
544
    OGRErr DeleteLayer(int) override;
545
546
    char **GetFileList() override;
547
548
    std::shared_ptr<GDALGroup> GetRootGroup() const override
549
0
    {
550
0
        return m_poRootGroup;
551
0
    }
552
553
    OGRErr StartTransaction(int bForce) override;
554
    OGRErr CommitTransaction() override;
555
    OGRErr RollbackTransaction() override;
556
557
    const CPLStringList &GetSubdatasets() const
558
6.41k
    {
559
6.41k
        return m_aosSubdatasets;
560
6.41k
    }
561
562
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
563
    const OGRSpatialReference *GetSpatialRef() const override;
564
565
    CSLConstList GetMetadata(const char *pszDomain = "") override;
566
567
    bool AddFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain,
568
                        std::string &failureReason) override;
569
570
    bool DeleteFieldDomain(const std::string &name,
571
                           std::string &failureReason) override;
572
573
    bool UpdateFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain,
574
                           std::string &failureReason) override;
575
576
    std::vector<std::string>
577
    GetRelationshipNames(CSLConstList papszOptions = nullptr) const override;
578
579
    const GDALRelationship *
580
    GetRelationship(const std::string &name) const override;
581
582
    bool AddRelationship(std::unique_ptr<GDALRelationship> &&relationship,
583
                         std::string &failureReason) override;
584
585
    bool DeleteRelationship(const std::string &name,
586
                            std::string &failureReason) override;
587
588
    bool UpdateRelationship(std::unique_ptr<GDALRelationship> &&relationship,
589
                            std::string &failureReason) override;
590
591
    bool GetExistingSpatialRef(const std::string &osWKT, double dfXOrigin,
592
                               double dfYOrigin, double dfXYScale,
593
                               double dfZOrigin, double dfZScale,
594
                               double dfMOrigin, double dfMScale,
595
                               double dfXYTolerance, double dfZTolerance,
596
                               double dfMTolerance);
597
598
    bool AddNewSpatialRef(const std::string &osWKT, double dfXOrigin,
599
                          double dfYOrigin, double dfXYScale, double dfZOrigin,
600
                          double dfZScale, double dfMOrigin, double dfMScale,
601
                          double dfXYTolerance, double dfZTolerance,
602
                          double dfMTolerance);
603
604
    bool RegisterLayerInSystemCatalog(const std::string &osLayerName);
605
606
    bool RegisterInItemRelationships(const std::string &osOriginGUID,
607
                                     const std::string &osDestGUID,
608
                                     const std::string &osTypeGUID);
609
610
    bool RegisterRelationshipInItemRelationships(
611
        const std::string &osRelationshipGUID, const std::string &osOriginGUID,
612
        const std::string &osDestGUID);
613
614
    bool RemoveRelationshipFromItemRelationships(
615
        const std::string &osRelationshipGUID);
616
617
    bool RegisterFeatureDatasetInItems(const std::string &osFeatureDatasetGUID,
618
                                       const std::string &osName,
619
                                       const char *pszXMLDefinition);
620
621
    bool FindUUIDFromName(const std::string &osFeatureDatasetName,
622
                          std::string &osUUIDOut);
623
624
    bool RegisterFeatureClassInItems(const std::string &osLayerGUID,
625
                                     const std::string &osLayerName,
626
                                     const std::string &osPath,
627
                                     const FileGDBTable *poLyrTable,
628
                                     const char *pszXMLDefinition,
629
                                     const char *pszDocumentation);
630
631
    bool RegisterASpatialTableInItems(const std::string &osLayerGUID,
632
                                      const std::string &osLayerName,
633
                                      const std::string &osPath,
634
                                      const char *pszXMLDefinition,
635
                                      const char *pszDocumentation);
636
637
    bool LinkDomainToTable(const std::string &osDomainName,
638
                           const std::string &osLayerGUID);
639
    bool UnlinkDomainToTable(const std::string &osDomainName,
640
                             const std::string &osLayerGUID);
641
642
    bool UpdateXMLDefinition(const std::string &osLayerName,
643
                             const char *pszXMLDefinition);
644
645
    bool IsInTransaction() const
646
844k
    {
647
844k
        return m_bInTransaction;
648
844k
    }
649
650
    const std::string &GetBackupDirName() const
651
0
    {
652
0
        return m_osTransactionBackupDirname;
653
0
    }
654
655
    OGRSpatialReferenceRefCountedPtr BuildSRS(const CPLXMLNode *psInfo);
656
    OGRSpatialReferenceRefCountedPtr BuildSRS(const char *pszWKT);
657
};
658
659
/************************************************************************/
660
/*                   OGROpenFileGDBSingleFeatureLayer                   */
661
/************************************************************************/
662
663
class OGROpenFileGDBSingleFeatureLayer final : public OGRLayer
664
{
665
  private:
666
    char *pszVal;
667
    OGRFeatureDefn *poFeatureDefn;
668
    int iNextShapeId;
669
670
    CPL_DISALLOW_COPY_ASSIGN(OGROpenFileGDBSingleFeatureLayer)
671
672
  public:
673
    OGROpenFileGDBSingleFeatureLayer(const char *pszLayerName,
674
                                     const char *pszVal);
675
    ~OGROpenFileGDBSingleFeatureLayer() override;
676
677
    void ResetReading() override
678
0
    {
679
0
        iNextShapeId = 0;
680
0
    }
681
682
    OGRFeature *GetNextFeature() override;
683
684
    const OGRFeatureDefn *GetLayerDefn() const override
685
0
    {
686
0
        return poFeatureDefn;
687
0
    }
688
689
    int TestCapability(const char *) const override
690
0
    {
691
0
        return FALSE;
692
0
    }
693
};
694
695
/************************************************************************/
696
/*                 GDALOpenFileGDBRasterAttributeTable                  */
697
/************************************************************************/
698
699
class GDALOpenFileGDBRasterAttributeTable final
700
    : public GDALRasterAttributeTable
701
{
702
    std::unique_ptr<OGROpenFileGDBDataSource> m_poDS{};
703
    const std::string m_osVATTableName;
704
    std::unique_ptr<OGRLayer> m_poVATLayer{};
705
    mutable std::string m_osCachedValue{};
706
    mutable std::vector<GByte> m_abyCachedWKB{};
707
708
    GDALOpenFileGDBRasterAttributeTable(
709
        const GDALOpenFileGDBRasterAttributeTable &) = delete;
710
    GDALOpenFileGDBRasterAttributeTable &
711
    operator=(const GDALOpenFileGDBRasterAttributeTable &) = delete;
712
713
  public:
714
    GDALOpenFileGDBRasterAttributeTable(
715
        std::unique_ptr<OGROpenFileGDBDataSource> &&poDS,
716
        const std::string &osVATTableName,
717
        std::unique_ptr<OGRLayer> &&poVATLayer)
718
0
        : m_poDS(std::move(poDS)), m_osVATTableName(osVATTableName),
719
0
          m_poVATLayer(std::move(poVATLayer))
720
0
    {
721
0
    }
722
723
    GDALRasterAttributeTable *Clone() const override;
724
725
    int GetColumnCount() const override
726
0
    {
727
0
        return m_poVATLayer->GetLayerDefn()->GetFieldCount();
728
0
    }
729
730
    int GetRowCount() const override
731
0
    {
732
0
        return static_cast<int>(m_poVATLayer->GetFeatureCount());
733
0
    }
734
735
    const char *GetNameOfCol(int iCol) const override
736
0
    {
737
0
        if (iCol < 0 || iCol >= GetColumnCount())
738
0
            return nullptr;
739
0
        return m_poVATLayer->GetLayerDefn()->GetFieldDefn(iCol)->GetNameRef();
740
0
    }
741
742
    GDALRATFieldUsage GetUsageOfCol(int iCol) const override
743
0
    {
744
0
        const char *pszColName = GetNameOfCol(iCol);
745
0
        return pszColName && EQUAL(pszColName, "Value")   ? GFU_MinMax
746
0
               : pszColName && EQUAL(pszColName, "Count") ? GFU_PixelCount
747
0
                                                          : GFU_Generic;
748
0
    }
749
750
    int GetColOfUsage(GDALRATFieldUsage eUsage) const override
751
0
    {
752
0
        if (eUsage == GFU_MinMax)
753
0
            return m_poVATLayer->GetLayerDefn()->GetFieldIndex("Value");
754
0
        if (eUsage == GFU_PixelCount)
755
0
            return m_poVATLayer->GetLayerDefn()->GetFieldIndex("Count");
756
0
        return -1;
757
0
    }
758
759
    GDALRATFieldType GetTypeOfCol(int iCol) const override
760
0
    {
761
0
        if (iCol < 0 || iCol >= GetColumnCount())
762
0
            return GFT_Integer;
763
0
        switch (m_poVATLayer->GetLayerDefn()->GetFieldDefn(iCol)->GetType())
764
0
        {
765
0
            case OFTInteger:
766
0
            {
767
0
                if (m_poVATLayer->GetLayerDefn()
768
0
                        ->GetFieldDefn(iCol)
769
0
                        ->GetSubType() == OFSTBoolean)
770
0
                    return GFT_Boolean;
771
0
                return GFT_Integer;
772
0
            }
773
0
            case OFTReal:
774
0
                return GFT_Real;
775
0
            case OFTDateTime:
776
0
                return GFT_DateTime;
777
0
            default:
778
0
                break;
779
0
        }
780
0
        return GFT_String;
781
0
    }
782
783
    const char *GetValueAsString(int iRow, int iField) const override
784
0
    {
785
0
        auto poFeat =
786
0
            std::unique_ptr<OGRFeature>(m_poVATLayer->GetFeature(iRow + 1));
787
0
        if (!poFeat || iField >= poFeat->GetFieldCount())
788
0
            return "";
789
0
        m_osCachedValue = poFeat->GetFieldAsString(iField);
790
0
        return m_osCachedValue.c_str();
791
0
    }
792
793
    int GetValueAsInt(int iRow, int iField) const override
794
0
    {
795
0
        auto poFeat =
796
0
            std::unique_ptr<OGRFeature>(m_poVATLayer->GetFeature(iRow + 1));
797
0
        if (!poFeat || iField >= poFeat->GetFieldCount())
798
0
            return 0;
799
0
        return poFeat->GetFieldAsInteger(iField);
800
0
    }
801
802
    double GetValueAsDouble(int iRow, int iField) const override
803
0
    {
804
0
        auto poFeat =
805
0
            std::unique_ptr<OGRFeature>(m_poVATLayer->GetFeature(iRow + 1));
806
0
        if (!poFeat || iField >= poFeat->GetFieldCount())
807
0
            return 0;
808
0
        return poFeat->GetFieldAsDouble(iField);
809
0
    }
810
811
    bool GetValueAsBoolean(int iRow, int iField) const override
812
0
    {
813
0
        auto poFeat =
814
0
            std::unique_ptr<OGRFeature>(m_poVATLayer->GetFeature(iRow + 1));
815
0
        if (!poFeat || iField >= poFeat->GetFieldCount())
816
0
            return 0;
817
0
        return poFeat->GetFieldAsInteger(iField) != 0;
818
0
    }
819
820
    GDALRATDateTime GetValueAsDateTime(int iRow, int iField) const override
821
0
    {
822
0
        GDALRATDateTime dt;
823
0
        auto poFeat =
824
0
            std::unique_ptr<OGRFeature>(m_poVATLayer->GetFeature(iRow + 1));
825
0
        int nTZFlag = 0;
826
0
        if (poFeat && iField < poFeat->GetFieldCount() &&
827
0
            poFeat->GetFieldAsDateTime(iField, &dt.nYear, &dt.nMonth, &dt.nDay,
828
0
                                       &dt.nHour, &dt.nMinute, &dt.fSecond,
829
0
                                       &nTZFlag))
830
0
        {
831
0
            dt.bIsValid = true;
832
0
            dt.bPositiveTimeZone = nTZFlag <= 2 ? false : nTZFlag >= 100;
833
0
            dt.nTimeZoneHour = nTZFlag <= 2 ? 0 : std::abs(nTZFlag - 100) / 4;
834
0
            dt.nTimeZoneMinute =
835
0
                nTZFlag <= 2 ? 0 : (std::abs(nTZFlag - 100) % 4) * 15;
836
0
        }
837
0
        return dt;
838
0
    }
839
840
    const GByte *GetValueAsWKBGeometry(int iRow, int iField,
841
                                       size_t &nWKBSize) const override
842
0
    {
843
0
        const char *pszWKT = GetValueAsString(iRow, iField);
844
0
        if (pszWKT)
845
0
            m_abyCachedWKB = WKTGeometryToWKB(pszWKT);
846
0
        else
847
0
            m_abyCachedWKB.clear();
848
0
        nWKBSize = m_abyCachedWKB.size();
849
0
        return m_abyCachedWKB.data();
850
0
    }
851
852
    CPLErr SetValue(int, int, const char *) override
853
0
    {
854
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetValue() not supported");
855
0
        return CE_Failure;
856
0
    }
857
858
    CPLErr SetValue(int, int, int) override
859
0
    {
860
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetValue() not supported");
861
0
        return CE_Failure;
862
0
    }
863
864
    CPLErr SetValue(int, int, double) override
865
0
    {
866
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetValue() not supported");
867
0
        return CE_Failure;
868
0
    }
869
870
    CPLErr SetValue(int, int, bool) override
871
0
    {
872
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetValue() not supported");
873
0
        return CE_Failure;
874
0
    }
875
876
    CPLErr SetValue(int, int, const GDALRATDateTime &) override
877
0
    {
878
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetValue() not supported");
879
0
        return CE_Failure;
880
0
    }
881
882
    CPLErr SetValue(int, int, const void *, size_t) override
883
0
    {
884
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetValue() not supported");
885
0
        return CE_Failure;
886
0
    }
887
888
    int ChangesAreWrittenToFile() override
889
0
    {
890
0
        return false;
891
0
    }
892
893
    CPLErr SetTableType(const GDALRATTableType) override
894
0
    {
895
0
        CPLError(CE_Failure, CPLE_NotSupported, "SetTableType() not supported");
896
0
        return CE_Failure;
897
0
    }
898
899
    GDALRATTableType GetTableType() const override
900
0
    {
901
0
        return GRTT_THEMATIC;
902
0
    }
903
904
    void RemoveStatistics() override
905
0
    {
906
0
        CPLError(CE_Failure, CPLE_NotSupported,
907
0
                 "RemoveStatistics() not supported");
908
0
    }
909
};
910
911
/************************************************************************/
912
/*                      GDALOpenFileGDBRasterBand                       */
913
/************************************************************************/
914
915
class GDALOpenFileGDBRasterBand final : public GDALRasterBand
916
{
917
    friend class OGROpenFileGDBDataSource;
918
    std::vector<GByte> m_abyTmpBuffer{};
919
    int m_nBitWidth = 0;
920
    int m_nOverviewLevel = 0;
921
    std::vector<std::unique_ptr<GDALOpenFileGDBRasterBand>>
922
        m_apoOverviewBands{};
923
    bool m_bIsMask = false;
924
    std::unique_ptr<GDALOpenFileGDBRasterBand> m_poMaskBandOwned{};
925
    GDALOpenFileGDBRasterBand *m_poMainBand = nullptr;
926
    GDALOpenFileGDBRasterBand *m_poMaskBand = nullptr;
927
    bool m_bHasNoData = false;
928
    double m_dfNoData = 0.0;
929
    std::unique_ptr<GDALRasterAttributeTable> m_poRAT{};
930
931
    CPL_DISALLOW_COPY_ASSIGN(GDALOpenFileGDBRasterBand)
932
933
  public:
934
    GDALOpenFileGDBRasterBand(OGROpenFileGDBDataSource *poDSIn, int nBandIn,
935
                              GDALDataType eDT, int nBitWidth, int nBlockWidth,
936
                              int nBlockHeight, int nOverviewLevel,
937
                              bool bIsMask);
938
939
  protected:
940
    CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) override;
941
942
    int GetOverviewCount() override
943
0
    {
944
0
        return static_cast<int>(m_apoOverviewBands.size());
945
0
    }
946
947
    GDALRasterBand *GetOverview(int i) override
948
0
    {
949
0
        return (i >= 0 && i < GetOverviewCount()) ? m_apoOverviewBands[i].get()
950
0
                                                  : nullptr;
951
0
    }
952
953
    GDALRasterBand *GetMaskBand() override
954
0
    {
955
0
        return m_poMaskBand ? m_poMaskBand : GDALRasterBand::GetMaskBand();
956
0
    }
957
958
    int GetMaskFlags() override
959
0
    {
960
0
        return m_poMaskBand ? GMF_PER_DATASET : GDALRasterBand::GetMaskFlags();
961
0
    }
962
963
    double GetNoDataValue(int *pbHasNoData) override
964
0
    {
965
0
        if (pbHasNoData)
966
0
            *pbHasNoData = m_bHasNoData;
967
0
        return m_dfNoData;
968
0
    }
969
970
    GDALRasterAttributeTable *GetDefaultRAT() override;
971
};
972
973
#endif /* ndef OGR_OPENFILEGDB_H_INCLUDED */