/src/gdal/ogr/ogrsf_frmts/openfilegdb/filegdbtable.h
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implements reading of FileGDB tables |
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 FILEGDBTABLE_H_INCLUDED |
14 | | #define FILEGDBTABLE_H_INCLUDED |
15 | | |
16 | | #include "ogr_core.h" |
17 | | #include "cpl_progress.h" |
18 | | #include "cpl_vsi.h" |
19 | | #include "ogr_geometry.h" |
20 | | |
21 | | #include <limits> |
22 | | #include <string> |
23 | | #include <vector> |
24 | | |
25 | | namespace OpenFileGDB |
26 | | { |
27 | | constexpr uint64_t OFFSET_MINUS_ONE = static_cast<uint64_t>(-1); |
28 | | constexpr int MAX_CAR_COUNT_INDEXED_STR = 80; |
29 | | |
30 | | /************************************************************************/ |
31 | | /* FileGDBTableGeometryType */ |
32 | | /************************************************************************/ |
33 | | |
34 | | /* FGTGT = (F)ile(G)DB(T)able(G)eometry(T)ype */ |
35 | | typedef enum |
36 | | { |
37 | | FGTGT_NONE = 0, |
38 | | FGTGT_POINT = 1, |
39 | | FGTGT_MULTIPOINT = 2, |
40 | | FGTGT_LINE = 3, |
41 | | FGTGT_POLYGON = 4, |
42 | | FGTGT_MULTIPATCH = 9 |
43 | | } FileGDBTableGeometryType; |
44 | | |
45 | | /************************************************************************/ |
46 | | /* FileGDBFieldType */ |
47 | | /************************************************************************/ |
48 | | |
49 | | /* FGFT = (F)ile(G)DB(F)ield(T)ype */ |
50 | | typedef enum |
51 | | { |
52 | | FGFT_UNDEFINED = -1, |
53 | | FGFT_INT16 = 0, |
54 | | FGFT_INT32 = 1, |
55 | | FGFT_FLOAT32 = 2, |
56 | | FGFT_FLOAT64 = 3, |
57 | | FGFT_STRING = 4, |
58 | | FGFT_DATETIME = 5, |
59 | | FGFT_OBJECTID = 6, |
60 | | FGFT_GEOMETRY = 7, |
61 | | FGFT_BINARY = 8, |
62 | | FGFT_RASTER = 9, |
63 | | FGFT_GUID = 10, |
64 | | FGFT_GLOBALID = 11, |
65 | | FGFT_XML = 12, |
66 | | FGFT_INT64 = 13, // added in ArcGIS Pro 3.2 |
67 | | FGFT_DATE = 14, // added in ArcGIS Pro 3.2 |
68 | | FGFT_TIME = 15, // added in ArcGIS Pro 3.2 |
69 | | FGFT_DATETIME_WITH_OFFSET = 16, // added in ArcGIS Pro 3.2 |
70 | | } FileGDBFieldType; |
71 | | |
72 | | /************************************************************************/ |
73 | | /* FileGDBField */ |
74 | | /************************************************************************/ |
75 | | |
76 | | class FileGDBTable; |
77 | | class FileGDBIndex; |
78 | | |
79 | | class FileGDBField /* non final */ |
80 | | { |
81 | | friend class FileGDBTable; |
82 | | |
83 | | FileGDBTable *m_poParent = nullptr; |
84 | | |
85 | | std::string m_osName{}; |
86 | | std::string m_osAlias{}; |
87 | | FileGDBFieldType m_eType = FGFT_UNDEFINED; |
88 | | |
89 | | bool m_bNullable = false; // Bit 1 of flag field |
90 | | bool m_bRequired = |
91 | | false; // Bit 2 of flag field. Set for ObjectID, geometry field and Shape_Area/Shape_Length |
92 | | bool m_bEditable = false; // Bit 3 of flag field. |
93 | | bool m_bHighPrecision = false; // for FGFT_DATETIME |
94 | | bool m_bReadAsDouble = |
95 | | false; // used by FileGDBTable::CreateAttributeIndex() |
96 | | int m_nMaxWidth = 0; /* for string */ |
97 | | |
98 | | OGRField m_sDefault{}; |
99 | | |
100 | | FileGDBIndex *m_poIndex = nullptr; |
101 | | |
102 | | FileGDBField(const FileGDBField &) = delete; |
103 | | FileGDBField &operator=(const FileGDBField &) = delete; |
104 | | |
105 | | public: |
106 | | static const OGRField UNSET_FIELD; |
107 | | static constexpr int BIT_NULLABLE = 0; |
108 | | static constexpr int BIT_REQUIRED = 1; |
109 | | static constexpr int BIT_EDITABLE = 2; |
110 | | static constexpr int MASK_NULLABLE = 1 << BIT_NULLABLE; |
111 | | static constexpr int MASK_REQUIRED = 1 << BIT_REQUIRED; |
112 | | static constexpr int MASK_EDITABLE = 1 << BIT_EDITABLE; |
113 | | |
114 | | explicit FileGDBField(FileGDBTable *m_poParent); |
115 | | FileGDBField(const std::string &osName, const std::string &osAlias, |
116 | | FileGDBFieldType eType, bool bNullable, bool bRequired, |
117 | | bool bEditable, int nMaxWidth, const OGRField &sDefault); |
118 | | virtual ~FileGDBField(); |
119 | | |
120 | | void SetParent(FileGDBTable *poParent) |
121 | 83.5k | { |
122 | 83.5k | m_poParent = poParent; |
123 | 83.5k | } |
124 | | |
125 | | const std::string &GetName() const |
126 | 93.3M | { |
127 | 93.3M | return m_osName; |
128 | 93.3M | } |
129 | | |
130 | | const std::string &GetAlias() const |
131 | 1.91M | { |
132 | 1.91M | return m_osAlias; |
133 | 1.91M | } |
134 | | |
135 | | FileGDBFieldType GetType() const |
136 | 16.4M | { |
137 | 16.4M | return m_eType; |
138 | 16.4M | } |
139 | | |
140 | | bool IsNullable() const |
141 | 6.62M | { |
142 | 6.62M | return m_bNullable; |
143 | 6.62M | } |
144 | | |
145 | | bool IsRequired() const |
146 | 1.88M | { |
147 | 1.88M | return m_bRequired; |
148 | 1.88M | } |
149 | | |
150 | | bool IsEditable() const |
151 | 1.88M | { |
152 | 1.88M | return m_bEditable; |
153 | 1.88M | } |
154 | | |
155 | | int GetMaxWidth() const |
156 | 1.87M | { |
157 | 1.87M | return m_nMaxWidth; |
158 | 1.87M | } |
159 | | |
160 | | const OGRField *GetDefault() const |
161 | 1.92M | { |
162 | 1.92M | return &m_sDefault; |
163 | 1.92M | } |
164 | | |
165 | | void SetHighPrecision() |
166 | 0 | { |
167 | 0 | m_bHighPrecision = true; |
168 | 0 | } |
169 | | |
170 | | bool IsHighPrecision() const |
171 | 1.77M | { |
172 | 1.77M | return m_bHighPrecision; |
173 | 1.77M | } |
174 | | |
175 | | int HasIndex(); |
176 | | FileGDBIndex *GetIndex(); |
177 | | }; |
178 | | |
179 | | /************************************************************************/ |
180 | | /* FileGDBGeomField */ |
181 | | /************************************************************************/ |
182 | | |
183 | | class FileGDBGeomField /* non final */ : public FileGDBField |
184 | | { |
185 | | friend class FileGDBTable; |
186 | | |
187 | | static const double ESRI_NAN; |
188 | | |
189 | | std::string m_osWKT{}; |
190 | | int m_bHasZOriginScaleTolerance = 0; |
191 | | int m_bHasMOriginScaleTolerance = 0; |
192 | | double m_dfXOrigin = 0; |
193 | | double m_dfYOrigin = 0; |
194 | | double m_dfXYScale = 0; |
195 | | double m_dfMOrigin = 0; |
196 | | double m_dfMScale = 0; |
197 | | double m_dfZOrigin = 0; |
198 | | double m_dfZScale = 0; |
199 | | double m_dfXYTolerance = 0; |
200 | | double m_dfMTolerance = 0; |
201 | | double m_dfZTolerance = 0; |
202 | | double m_dfXMin = ESRI_NAN; |
203 | | double m_dfYMin = ESRI_NAN; |
204 | | double m_dfZMin = ESRI_NAN; |
205 | | double m_dfMMin = ESRI_NAN; |
206 | | double m_dfXMax = ESRI_NAN; |
207 | | double m_dfYMax = ESRI_NAN; |
208 | | double m_dfZMax = ESRI_NAN; |
209 | | double m_dfMMax = ESRI_NAN; |
210 | | std::vector<double> m_adfSpatialIndexGridResolution{}; |
211 | | |
212 | | public: |
213 | | explicit FileGDBGeomField(FileGDBTable *m_poParent); |
214 | | FileGDBGeomField(const std::string &osName, const std::string &osAlias, |
215 | | bool bNullable, const std::string &osWKT, double dfXOrigin, |
216 | | double dfYOrigin, double dfXYScale, double dfXYTolerance, |
217 | | const std::vector<double> &adfSpatialIndexGridResolution); |
218 | | |
219 | | ~FileGDBGeomField() override; |
220 | | |
221 | | const std::string &GetWKT() const |
222 | 34.2k | { |
223 | 34.2k | return m_osWKT; |
224 | 34.2k | } |
225 | | |
226 | | double GetXMin() const |
227 | 11.1k | { |
228 | 11.1k | return m_dfXMin; |
229 | 11.1k | } |
230 | | |
231 | | double GetYMin() const |
232 | 10.5k | { |
233 | 10.5k | return m_dfYMin; |
234 | 10.5k | } |
235 | | |
236 | | double GetZMin() const |
237 | 1.70k | { |
238 | 1.70k | return m_dfZMin; |
239 | 1.70k | } // only valid for m_bGeomTypeHasZ |
240 | | |
241 | | double GetMMin() const |
242 | 0 | { |
243 | 0 | return m_dfMMin; |
244 | 0 | } // only valid for m_bGeomTypeHasM |
245 | | |
246 | | double GetXMax() const |
247 | 10.5k | { |
248 | 10.5k | return m_dfXMax; |
249 | 10.5k | } |
250 | | |
251 | | double GetYMax() const |
252 | 10.5k | { |
253 | 10.5k | return m_dfYMax; |
254 | 10.5k | } |
255 | | |
256 | | double GetZMax() const |
257 | 1.70k | { |
258 | 1.70k | return m_dfZMax; |
259 | 1.70k | } // only valid for m_bGeomTypeHasZ |
260 | | |
261 | | double GetMMax() const |
262 | 0 | { |
263 | 0 | return m_dfMMax; |
264 | 0 | } // only valid for m_bGeomTypeHasM |
265 | | |
266 | | void SetXYMinMax(double dfXMin, double dfYMin, double dfXMax, |
267 | | double dfYMax); |
268 | | void SetZMinMax(double dfZMin, double dfZMax); |
269 | | void SetMMinMax(double dfMMin, double dfMMax); |
270 | | |
271 | | int HasZOriginScaleTolerance() const |
272 | 11.0k | { |
273 | 11.0k | return m_bHasZOriginScaleTolerance; |
274 | 11.0k | } |
275 | | |
276 | | int HasMOriginScaleTolerance() const |
277 | 11.0k | { |
278 | 11.0k | return m_bHasMOriginScaleTolerance; |
279 | 11.0k | } |
280 | | |
281 | | double GetXOrigin() const |
282 | 2.27M | { |
283 | 2.27M | return m_dfXOrigin; |
284 | 2.27M | } |
285 | | |
286 | | double GetYOrigin() const |
287 | 2.27M | { |
288 | 2.27M | return m_dfYOrigin; |
289 | 2.27M | } |
290 | | |
291 | | double GetXYScale() const |
292 | 4.51M | { |
293 | 4.51M | return m_dfXYScale; |
294 | 4.51M | } |
295 | | |
296 | | double GetXYTolerance() const |
297 | 34.7k | { |
298 | 34.7k | return m_dfXYTolerance; |
299 | 34.7k | } |
300 | | |
301 | | double GetZOrigin() const |
302 | 517k | { |
303 | 517k | return m_dfZOrigin; |
304 | 517k | } |
305 | | |
306 | | double GetZScale() const |
307 | 132k | { |
308 | 132k | return m_dfZScale; |
309 | 132k | } |
310 | | |
311 | | double GetZTolerance() const |
312 | 34.7k | { |
313 | 34.7k | return m_dfZTolerance; |
314 | 34.7k | } |
315 | | |
316 | | void SetZOriginScaleTolerance(double dfZOrigin, double dfZScale, |
317 | | double dfZTolerance); |
318 | | |
319 | | double GetMOrigin() const |
320 | 693k | { |
321 | 693k | return m_dfMOrigin; |
322 | 693k | } |
323 | | |
324 | | double GetMScale() const |
325 | 143k | { |
326 | 143k | return m_dfMScale; |
327 | 143k | } |
328 | | |
329 | | double GetMTolerance() const |
330 | 34.7k | { |
331 | 34.7k | return m_dfMTolerance; |
332 | 34.7k | } |
333 | | |
334 | | void SetMOriginScaleTolerance(double dfMOrigin, double dfMScale, |
335 | | double dfMTolerance); |
336 | | |
337 | | const std::vector<double> &GetSpatialIndexGridResolution() const |
338 | 6.67k | { |
339 | 6.67k | return m_adfSpatialIndexGridResolution; |
340 | 6.67k | } |
341 | | }; |
342 | | |
343 | | /************************************************************************/ |
344 | | /* FileGDBRasterField */ |
345 | | /************************************************************************/ |
346 | | |
347 | | class FileGDBRasterField final : public FileGDBGeomField |
348 | | { |
349 | | public: |
350 | | enum class Type |
351 | | { |
352 | | EXTERNAL, |
353 | | MANAGED, |
354 | | INLINE, |
355 | | }; |
356 | | |
357 | | private: |
358 | | friend class FileGDBTable; |
359 | | |
360 | | std::string m_osRasterColumnName{}; |
361 | | |
362 | | Type m_eRasterType = Type::EXTERNAL; |
363 | | |
364 | | FileGDBRasterField(const FileGDBRasterField &) = delete; |
365 | | FileGDBRasterField &operator=(const FileGDBRasterField &) = delete; |
366 | | |
367 | | public: |
368 | | explicit FileGDBRasterField(FileGDBTable *poParentIn) |
369 | 875 | : FileGDBGeomField(poParentIn) |
370 | 875 | { |
371 | 875 | } |
372 | | |
373 | | ~FileGDBRasterField() override; |
374 | | |
375 | | const std::string &GetRasterColumnName() const |
376 | 0 | { |
377 | 0 | return m_osRasterColumnName; |
378 | 0 | } |
379 | | |
380 | | Type GetRasterType() const |
381 | 1.21M | { |
382 | 1.21M | return m_eRasterType; |
383 | 1.21M | } |
384 | | }; |
385 | | |
386 | | /************************************************************************/ |
387 | | /* FileGDBIndex */ |
388 | | /************************************************************************/ |
389 | | |
390 | | class FileGDBIndex |
391 | | { |
392 | | friend class FileGDBTable; |
393 | | std::string m_osIndexName{}; |
394 | | std::string m_osExpression{}; |
395 | | |
396 | | public: |
397 | 7.32k | FileGDBIndex() = default; |
398 | | |
399 | | ~FileGDBIndex(); |
400 | | |
401 | | const std::string &GetIndexName() const |
402 | 9.59k | { |
403 | 9.59k | return m_osIndexName; |
404 | 9.59k | } |
405 | | |
406 | | const std::string &GetExpression() const |
407 | 9.38k | { |
408 | 9.38k | return m_osExpression; |
409 | 9.38k | } |
410 | | |
411 | | std::string GetFieldName() const; |
412 | | int GetMaxWidthInBytes(const FileGDBTable *poTable) const; |
413 | | |
414 | | static std::string |
415 | | GetFieldNameFromExpression(const std::string &osExpression); |
416 | | }; |
417 | | |
418 | | /************************************************************************/ |
419 | | /* FileGDBTable */ |
420 | | /************************************************************************/ |
421 | | |
422 | | class FileGDBTable |
423 | | { |
424 | | VSILFILE *m_fpTable = nullptr; |
425 | | VSILFILE *m_fpTableX = nullptr; |
426 | | |
427 | | enum class GDBTableVersion |
428 | | { |
429 | | V3 = 3, // 32-bit object id |
430 | | V4 = 4, // 64-bit object id (ince ArcGIS Pro 3.2) |
431 | | }; |
432 | | GDBTableVersion m_eGDBTableVersion = GDBTableVersion::V3; |
433 | | vsi_l_offset m_nFileSize = 0; /* only read when needed */ |
434 | | bool m_bUpdate = false; |
435 | | bool m_bReliableObjectID = true; // can be set to false on some V4 files |
436 | | |
437 | | //! This flag is set when we detect that a corruption of m_nHeaderBufferMaxSize |
438 | | // prior to fix needs to fdf39012788b1110b3bf0ae6b8422a528f0ae8b6 to be |
439 | | // repaired |
440 | | bool m_bHasWarnedAboutHeaderRepair = false; |
441 | | |
442 | | std::string m_osFilename{}; |
443 | | std::string m_osFilenameWithLayerName{}; |
444 | | bool m_bIsV9 = false; |
445 | | std::vector<std::unique_ptr<FileGDBField>> m_apoFields{}; |
446 | | int m_iObjectIdField = -1; |
447 | | |
448 | | int m_bHasReadGDBIndexes = FALSE; |
449 | | std::vector<std::unique_ptr<FileGDBIndex>> m_apoIndexes{}; |
450 | | |
451 | | int m_nHasSpatialIndex = -1; |
452 | | |
453 | | bool m_bDirtyHeader = false; |
454 | | bool m_bDirtyFieldDescriptors = false; |
455 | | bool m_bDirtyIndices = false; |
456 | | bool m_bDirtyGdbIndexesFile = false; |
457 | | |
458 | | uint32_t m_nHeaderBufferMaxSize = 0; |
459 | | GUIntBig m_nOffsetFieldDesc = 0; |
460 | | GUInt32 m_nFieldDescLength = 0; |
461 | | bool m_bDirtyGeomFieldBBox = false; |
462 | | bool m_bDirtyGeomFieldSpatialIndexGridRes = false; |
463 | | uint32_t m_nGeomFieldBBoxSubOffset = |
464 | | 0; // offset of geometry field bounding box |
465 | | // relative to m_nOffsetFieldDesc |
466 | | uint32_t m_nGeomFieldSpatialIndexGridResSubOffset = |
467 | | 0; // offset of geometry field spatial index grid resolution |
468 | | // relative to m_nOffsetFieldDesc |
469 | | |
470 | | GUInt32 m_nTablxOffsetSize = |
471 | | 0; // 4 (4 GB limit), 5 (1 TB limit), 6 (256 TB limit) |
472 | | std::vector<vsi_l_offset> |
473 | | m_anFeatureOffsets{}; /* MSb set marks deleted feature. Only used when |
474 | | no .gdbtablx file */ |
475 | | |
476 | | uint64_t m_nOffsetTableXTrailer = 0; |
477 | | uint64_t m_n1024BlocksPresent = 0; |
478 | | std::vector<GByte> m_abyTablXBlockMap{}; |
479 | | int m_nCountBlocksBeforeIBlockIdx = 0; /* optimization */ |
480 | | int m_nCountBlocksBeforeIBlockValue = 0; /* optimization */ |
481 | | bool m_bDirtyTableXHeader = false; |
482 | | bool m_bDirtyTableXTrailer = false; |
483 | | |
484 | | int m_nHasFreeList = -1; |
485 | | bool m_bFreelistCanBeDeleted = false; |
486 | | |
487 | | char m_achGUIDBuffer[32 + 6 + 1]{0}; |
488 | | int m_nChSaved = -1; |
489 | | |
490 | | int m_bError = FALSE; |
491 | | int64_t m_nCurRow = -1; |
492 | | int m_bHasDeletedFeaturesListed = FALSE; |
493 | | bool m_bIsDeleted = false; |
494 | | int m_nLastCol = -1; |
495 | | GByte *m_pabyIterVals = nullptr; |
496 | | int m_iAccNullable = 0; |
497 | | GUInt32 m_nRowBlobLength = 0; |
498 | | OGRField m_sCurField{}; |
499 | | |
500 | | FileGDBTableGeometryType m_eTableGeomType = FGTGT_NONE; |
501 | | bool m_bGeomTypeHasZ = false; |
502 | | bool m_bGeomTypeHasM = false; |
503 | | bool m_bStringsAreUTF8 = true; // if false, UTF16 |
504 | | std::string m_osTempString{}; // used as a temporary to store strings |
505 | | // recoded from UTF16 to UTF8 |
506 | | int64_t m_nValidRecordCount = 0; |
507 | | int64_t m_nTotalRecordCount = 0; |
508 | | int m_iGeomField = -1; |
509 | | int m_nCountNullableFields = 0; |
510 | | unsigned m_nNullableFieldsSizeInBytes = 0; |
511 | | |
512 | | std::vector<double> m_adfSpatialIndexGridResolution{}; |
513 | | |
514 | | GUInt32 m_nRowBufferMaxSize = 0; |
515 | | std::vector<GByte> m_abyBuffer{}; |
516 | | std::vector<GByte> m_abyGeomBuffer{}; |
517 | | std::vector<GByte> m_abyCurvePart{}; |
518 | | std::vector<uint32_t> m_anNumberPointsPerPart{}; |
519 | | std::vector<double> m_adfX{}; |
520 | | std::vector<double> m_adfY{}; |
521 | | std::vector<double> m_adfZ{}; |
522 | | std::vector<double> m_adfM{}; |
523 | | |
524 | | std::string m_osCacheRasterFieldPath{}; |
525 | | |
526 | | GUIntBig m_nFilterXMin = 0, m_nFilterXMax = 0, m_nFilterYMin = 0, |
527 | | m_nFilterYMax = 0; |
528 | | |
529 | | class WholeFileRewriter |
530 | | { |
531 | | FileGDBTable &m_oTable; |
532 | | bool m_bModifyInPlace = false; |
533 | | std::string m_osGdbTablx{}; |
534 | | std::string m_osBackupValidFilename{}; |
535 | | std::string m_osBackupGdbTable{}; |
536 | | std::string m_osBackupGdbTablx{}; |
537 | | std::string m_osTmpGdbTable{}; |
538 | | std::string m_osTmpGdbTablx{}; |
539 | | bool m_bOldDirtyIndices = false; |
540 | | uint64_t m_nOldFileSize = 0; |
541 | | uint64_t m_nOldOffsetFieldDesc = 0; |
542 | | uint32_t m_nOldFieldDescLength = 0; |
543 | | bool m_bIsInit = false; |
544 | | |
545 | | WholeFileRewriter(const WholeFileRewriter &) = delete; |
546 | | WholeFileRewriter &operator=(const WholeFileRewriter &) = delete; |
547 | | |
548 | | public: |
549 | | VSILFILE *m_fpOldGdbtable = nullptr; |
550 | | VSILFILE *m_fpOldGdbtablx = nullptr; |
551 | | VSILFILE *m_fpTable = nullptr; |
552 | | VSILFILE *m_fpTableX = nullptr; |
553 | | |
554 | 559 | explicit WholeFileRewriter(FileGDBTable &oTable) : m_oTable(oTable) |
555 | 559 | { |
556 | 559 | } |
557 | | |
558 | | ~WholeFileRewriter(); |
559 | | |
560 | | bool Begin(); |
561 | | bool Commit(); |
562 | | void Rollback(); |
563 | | }; |
564 | | |
565 | | bool WriteHeader(VSILFILE *fpTable); |
566 | | bool WriteHeaderX(VSILFILE *fpTableX); |
567 | | |
568 | | bool ReadTableXHeaderV3(); |
569 | | bool ReadTableXHeaderV4(); |
570 | | int IsLikelyFeatureAtOffset(vsi_l_offset nOffset, GUInt32 *pnSize, |
571 | | int *pbDeletedRecord); |
572 | | bool GuessFeatureLocations(); |
573 | | bool WriteFieldDescriptors(VSILFILE *fpTable); |
574 | | bool SeekIntoTableXForNewFeature(int nObjectID); |
575 | | uint64_t ReadFeatureOffset(const GByte *pabyBuffer); |
576 | | void WriteFeatureOffset(uint64_t nFeatureOffset, GByte *pabyBuffer); |
577 | | bool WriteFeatureOffset(uint64_t nFeatureOffset); |
578 | | bool EncodeFeature(const std::vector<OGRField> &asRawFields, |
579 | | const OGRGeometry *poGeom, int iSkipField); |
580 | | bool EncodeGeometry(const FileGDBGeomField *poGeomField, |
581 | | const OGRGeometry *poGeom); |
582 | | bool RewriteTableToAddLastAddedField(); |
583 | | void CreateGdbIndexesFile(); |
584 | | void RemoveIndices(); |
585 | | void RefreshIndices(); |
586 | | bool CreateAttributeIndex(const FileGDBIndex *poIndex); |
587 | | uint64_t GetOffsetOfFreeAreaFromFreeList(uint32_t nSize); |
588 | | void AddEntryToFreelist(uint64_t nOffset, uint32_t nSize); |
589 | | |
590 | | FileGDBTable(const FileGDBTable &) = delete; |
591 | | FileGDBTable &operator=(const FileGDBTable &) = delete; |
592 | | |
593 | | public: |
594 | | FileGDBTable(); |
595 | | ~FileGDBTable(); |
596 | | |
597 | | bool Open(const char *pszFilename, bool bUpdate, |
598 | | const char *pszLayerName = nullptr); |
599 | | |
600 | | bool Create(const char *pszFilename, int nTablxOffsetSize, |
601 | | FileGDBTableGeometryType eTableGeomType, bool bGeomTypeHasZ, |
602 | | bool bGeomTypeHasM); |
603 | | bool SetTextUTF16(); |
604 | | |
605 | | bool Sync(VSILFILE *fpTable = nullptr, VSILFILE *fpTableX = nullptr); |
606 | | bool Repack(GDALProgressFunc pfnProgress, void *pProgressData); |
607 | | void RecomputeExtent(); |
608 | | |
609 | | //! Object should no longer be used after Close() |
610 | | void Close(); |
611 | | |
612 | | bool IsFileGDBV9() const |
613 | 0 | { |
614 | 0 | return m_bIsV9; |
615 | 0 | } |
616 | | |
617 | | const std::string &GetFilename() const |
618 | 0 | { |
619 | 0 | return m_osFilename; |
620 | 0 | } |
621 | | |
622 | | FileGDBTableGeometryType GetGeometryType() const |
623 | 43.7k | { |
624 | 43.7k | return m_eTableGeomType; |
625 | 43.7k | } |
626 | | |
627 | | bool GetGeomTypeHasZ() const |
628 | 6.42k | { |
629 | 6.42k | return m_bGeomTypeHasZ; |
630 | 6.42k | } |
631 | | |
632 | | bool GetGeomTypeHasM() const |
633 | 6.42k | { |
634 | 6.42k | return m_bGeomTypeHasM; |
635 | 6.42k | } |
636 | | |
637 | | int64_t GetValidRecordCount() const |
638 | 6.34k | { |
639 | 6.34k | return m_nValidRecordCount; |
640 | 6.34k | } |
641 | | |
642 | | int64_t GetTotalRecordCount() const |
643 | 1.82M | { |
644 | 1.82M | return m_nTotalRecordCount; |
645 | 1.82M | } |
646 | | |
647 | | int GetFieldCount() const |
648 | 3.83M | { |
649 | 3.83M | return static_cast<int>(m_apoFields.size()); |
650 | 3.83M | } |
651 | | |
652 | | FileGDBField *GetField(int i) const |
653 | 6.08M | { |
654 | 6.08M | return m_apoFields[i].get(); |
655 | 6.08M | } |
656 | | |
657 | | int GetGeomFieldIdx() const |
658 | 11.4k | { |
659 | 11.4k | return m_iGeomField; |
660 | 11.4k | } |
661 | | |
662 | | const FileGDBGeomField *GetGeomField() const |
663 | 35.0k | { |
664 | 35.0k | return (m_iGeomField >= 0) ? cpl::down_cast<FileGDBGeomField *>( |
665 | 35.0k | m_apoFields[m_iGeomField].get()) |
666 | 35.0k | : nullptr; |
667 | 35.0k | } |
668 | | |
669 | | int GetObjectIdFieldIdx() const |
670 | 927k | { |
671 | 927k | return m_iObjectIdField; |
672 | 927k | } |
673 | | |
674 | | int GetFieldIdx(const std::string &osName) const; |
675 | | |
676 | | int GetIndexCount(); |
677 | | |
678 | | const FileGDBIndex *GetIndex(int i) const |
679 | 0 | { |
680 | 0 | return m_apoIndexes[i].get(); |
681 | 0 | } |
682 | | |
683 | | /** Return if we can use attribute or spatial indices. |
684 | | * This can be false for some sparse tables with 64-bit ObjectID since |
685 | | * the format of the sparse bitmap isn't fully understood yet. |
686 | | */ |
687 | | bool CanUseIndices() const |
688 | 6.68k | { |
689 | 6.68k | return m_bReliableObjectID; |
690 | 6.68k | } |
691 | | |
692 | | bool HasSpatialIndex(); |
693 | | bool CreateIndex(const std::string &osIndexName, |
694 | | const std::string &osExpression); |
695 | | void ComputeOptimalSpatialIndexGridResolution(); |
696 | | bool CreateSpatialIndex(); |
697 | | |
698 | | vsi_l_offset |
699 | | GetOffsetInTableForRow(int64_t iRow, |
700 | | vsi_l_offset *pnOffsetInTableX = nullptr); |
701 | | |
702 | | int HasDeletedFeaturesListed() const |
703 | 191k | { |
704 | 191k | return m_bHasDeletedFeaturesListed; |
705 | 191k | } |
706 | | |
707 | | /* Next call to SelectRow() or GetFieldValue() invalidates previously |
708 | | * returned values */ |
709 | | bool SelectRow(int64_t iRow, bool bWarnOnlyOnDeletedRows = false); |
710 | | int64_t GetAndSelectNextNonEmptyRow(int64_t iRow); |
711 | | |
712 | | int HasGotError() const |
713 | 2.67M | { |
714 | 2.67M | return m_bError; |
715 | 2.67M | } |
716 | | |
717 | | int64_t GetCurRow() const |
718 | 182k | { |
719 | 182k | return m_nCurRow; |
720 | 182k | } |
721 | | |
722 | | bool IsCurRowDeleted() const |
723 | 0 | { |
724 | 0 | return m_bIsDeleted; |
725 | 0 | } |
726 | | |
727 | | const OGRField *GetFieldValue(int iCol); |
728 | | std::vector<OGRField> GetAllFieldValues(); |
729 | | void FreeAllFieldValues(std::vector<OGRField> &asFields); |
730 | | |
731 | | int GetFeatureExtent(const OGRField *psGeomField, |
732 | | OGREnvelope *psOutFeatureEnvelope); |
733 | | |
734 | | const std::vector<double> &GetSpatialIndexGridResolution() const |
735 | 0 | { |
736 | 0 | return m_adfSpatialIndexGridResolution; |
737 | 0 | } |
738 | | |
739 | | void InstallFilterEnvelope(const OGREnvelope *psFilterEnvelope); |
740 | | int DoesGeometryIntersectsFilterEnvelope(const OGRField *psGeomField); |
741 | | |
742 | | void GetMinMaxProjYForSpatialIndex(double &dfYMin, double &dfYMax) const; |
743 | | |
744 | | bool CreateField(std::unique_ptr<FileGDBField> &&psField); |
745 | | bool DeleteField(int iField); |
746 | | bool AlterField(int iField, const std::string &osName, |
747 | | const std::string &osAlias, FileGDBFieldType eType, |
748 | | bool bNullable, int nMaxWidth, const OGRField &sDefault); |
749 | | bool AlterGeomField(const std::string &osName, const std::string &osAlias, |
750 | | bool bNullable, const std::string &osWKT); |
751 | | |
752 | | bool CreateFeature(const std::vector<OGRField> &asRawFields, |
753 | | const OGRGeometry *poGeom, int *pnFID = nullptr); |
754 | | bool UpdateFeature(int64_t nFID, const std::vector<OGRField> &asRawFields, |
755 | | const OGRGeometry *poGeom); |
756 | | bool DeleteFeature(int64_t nFID); |
757 | | |
758 | | bool CheckFreeListConsistency(); |
759 | | void DeleteFreeList(); |
760 | | }; |
761 | | |
762 | | /************************************************************************/ |
763 | | /* FileGDBSQLOp */ |
764 | | /************************************************************************/ |
765 | | |
766 | | typedef enum |
767 | | { |
768 | | FGSO_ISNOTNULL, |
769 | | FGSO_LT, |
770 | | FGSO_LE, |
771 | | FGSO_EQ, |
772 | | FGSO_GE, |
773 | | FGSO_GT, |
774 | | FGSO_ILIKE |
775 | | } FileGDBSQLOp; |
776 | | |
777 | | /************************************************************************/ |
778 | | /* FileGDBIterator */ |
779 | | /************************************************************************/ |
780 | | |
781 | | class FileGDBIterator /* non final */ |
782 | | { |
783 | | public: |
784 | 0 | virtual ~FileGDBIterator() = default; |
785 | | |
786 | | virtual FileGDBTable *GetTable() = 0; |
787 | | virtual void Reset() = 0; |
788 | | virtual int64_t GetNextRowSortedByFID() = 0; |
789 | | virtual int64_t GetRowCount(); |
790 | | |
791 | | /* Only available on a BuildIsNotNull() iterator */ |
792 | | virtual const OGRField *GetMinValue(int &eOutOGRFieldType); |
793 | | virtual const OGRField *GetMaxValue(int &eOutOGRFieldType); |
794 | | /* will reset the iterator */ |
795 | | virtual bool GetMinMaxSumCount(double &dfMin, double &dfMax, double &dfSum, |
796 | | int &nCount); |
797 | | |
798 | | /* Only available on a BuildIsNotNull() or Build() iterator */ |
799 | | virtual int64_t GetNextRowSortedByValue(); |
800 | | |
801 | | static FileGDBIterator *Build(FileGDBTable *poParent, int nFieldIdx, |
802 | | int bAscending, FileGDBSQLOp op, |
803 | | OGRFieldType eOGRFieldType, |
804 | | const OGRField *psValue); |
805 | | static FileGDBIterator *BuildIsNotNull(FileGDBTable *poParent, |
806 | | int nFieldIdx, int bAscending); |
807 | | static FileGDBIterator *BuildNot(FileGDBIterator *poIterBase); |
808 | | static FileGDBIterator *BuildAnd(FileGDBIterator *poIter1, |
809 | | FileGDBIterator *poIter2, |
810 | | bool bTakeOwnershipOfIterators); |
811 | | static FileGDBIterator *BuildOr(FileGDBIterator *poIter1, |
812 | | FileGDBIterator *poIter2, |
813 | | int bIteratorAreExclusive = FALSE); |
814 | | }; |
815 | | |
816 | | /************************************************************************/ |
817 | | /* FileGDBSpatialIndexIterator */ |
818 | | /************************************************************************/ |
819 | | |
820 | | class FileGDBSpatialIndexIterator /* non final */ |
821 | | : virtual public FileGDBIterator |
822 | | { |
823 | | public: |
824 | | virtual bool SetEnvelope(const OGREnvelope &sFilterEnvelope) = 0; |
825 | | |
826 | | ~FileGDBSpatialIndexIterator() override; |
827 | | |
828 | | static FileGDBSpatialIndexIterator * |
829 | | Build(FileGDBTable *poParent, const OGREnvelope &sFilterEnvelope); |
830 | | }; |
831 | | |
832 | | /************************************************************************/ |
833 | | /* FileGDBOGRGeometryConverter */ |
834 | | /************************************************************************/ |
835 | | |
836 | | class FileGDBOGRGeometryConverter /* non final */ |
837 | | { |
838 | | public: |
839 | | virtual ~FileGDBOGRGeometryConverter(); |
840 | | |
841 | | virtual OGRGeometry *GetAsGeometry(const OGRField *psField) = 0; |
842 | | |
843 | | static FileGDBOGRGeometryConverter * |
844 | | BuildConverter(const FileGDBGeomField *poGeomField); |
845 | | static OGRwkbGeometryType |
846 | | GetGeometryTypeFromESRI(const char *pszESRIGeometryType); |
847 | | }; |
848 | | |
849 | | int FileGDBDoubleDateToOGRDate(double dfVal, bool bHighPrecision, |
850 | | OGRField *psField); |
851 | | int FileGDBDoubleTimeToOGRTime(double dfVal, OGRField *psField); |
852 | | int FileGDBDateTimeWithOffsetToOGRDate(double dfVal, int16_t nUTCOffset, |
853 | | OGRField *psField); |
854 | | |
855 | | } /* namespace OpenFileGDB */ |
856 | | |
857 | | #endif /* ndef FILEGDBTABLE_H_INCLUDED */ |