/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 >) 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 */ |