Coverage Report

Created: 2025-08-11 09:23

/src/gdal/ogr/ogrsf_frmts/openfilegdb/filegdbtable_priv.h
Line
Count
Source (jump to first uncovered line)
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_PRIV_H_INCLUDED
14
#define FILEGDBTABLE_PRIV_H_INCLUDED
15
16
#include "filegdbtable.h"
17
18
#include "cpl_conv.h"
19
#include "cpl_error.h"
20
#include "cpl_time.h"
21
22
#include <algorithm>
23
#include <cwchar>
24
#include <vector>
25
#include <limits>
26
27
584k
#define DIV_ROUND_UP(a, b) (((a) % (b)) == 0 ? ((a) / (b)) : (((a) / (b)) + 1))
28
29
16.5M
#define TEST_BIT(ar, bit) (ar[(bit) / 8] & (1 << ((bit) % 8)))
30
57.2k
#define BIT_ARRAY_SIZE_IN_BYTES(bitsize) (((bitsize) + 7) / 8)
31
32
namespace OpenFileGDB
33
{
34
35
/************************************************************************/
36
/*                              GetInt16()                              */
37
/************************************************************************/
38
39
inline GInt16 GetInt16(const GByte *pBaseAddr, int iOffset)
40
36.4k
{
41
36.4k
    GInt16 nVal;
42
36.4k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
43
36.4k
    CPL_LSBPTR16(&nVal);
44
36.4k
    return nVal;
45
36.4k
}
46
47
/************************************************************************/
48
/*                              GetUInt16()                             */
49
/************************************************************************/
50
51
inline GUInt16 GetUInt16(const GByte *pBaseAddr, int iOffset)
52
73.9k
{
53
73.9k
    GUInt16 nVal;
54
73.9k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
55
73.9k
    CPL_LSBPTR16(&nVal);
56
73.9k
    return nVal;
57
73.9k
}
58
59
/************************************************************************/
60
/*                              GetInt32()                              */
61
/************************************************************************/
62
63
inline GInt32 GetInt32(const GByte *pBaseAddr, int iOffset)
64
417k
{
65
417k
    GInt32 nVal;
66
417k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
67
417k
    CPL_LSBPTR32(&nVal);
68
417k
    return nVal;
69
417k
}
70
71
/************************************************************************/
72
/*                              GetUInt32()                             */
73
/************************************************************************/
74
75
inline GUInt32 GetUInt32(const GByte *pBaseAddr, int iOffset)
76
81.9M
{
77
81.9M
    GUInt32 nVal;
78
81.9M
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
79
81.9M
    CPL_LSBPTR32(&nVal);
80
81.9M
    return nVal;
81
81.9M
}
82
83
/************************************************************************/
84
/*                              GetInt64()                              */
85
/************************************************************************/
86
87
inline int64_t GetInt64(const GByte *pBaseAddr, int iOffset)
88
1.91k
{
89
1.91k
    int64_t nVal;
90
1.91k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
91
1.91k
    CPL_LSBPTR64(&nVal);
92
1.91k
    return nVal;
93
1.91k
}
94
95
/************************************************************************/
96
/*                              GetUInt64()                             */
97
/************************************************************************/
98
99
inline uint64_t GetUInt64(const GByte *pBaseAddr, int iOffset)
100
47.6k
{
101
47.6k
    uint64_t nVal;
102
47.6k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
103
47.6k
    CPL_LSBPTR64(&nVal);
104
47.6k
    return nVal;
105
47.6k
}
106
107
/************************************************************************/
108
/*                             GetFloat32()                             */
109
/************************************************************************/
110
111
inline float GetFloat32(const GByte *pBaseAddr, int iOffset)
112
22.8k
{
113
22.8k
    float fVal;
114
22.8k
    memcpy(&fVal, pBaseAddr + sizeof(fVal) * iOffset, sizeof(fVal));
115
22.8k
    CPL_LSBPTR32(&fVal);
116
22.8k
    return fVal;
117
22.8k
}
118
119
/************************************************************************/
120
/*                             GetFloat64()                             */
121
/************************************************************************/
122
123
inline double GetFloat64(const GByte *pBaseAddr, int iOffset)
124
707k
{
125
707k
    double dfVal;
126
707k
    memcpy(&dfVal, pBaseAddr + sizeof(dfVal) * iOffset, sizeof(dfVal));
127
707k
    CPL_LSBPTR64(&dfVal);
128
707k
    return dfVal;
129
707k
}
130
131
/************************************************************************/
132
/*                          ReadUInt32()                                */
133
/************************************************************************/
134
135
inline bool ReadUInt32(VSILFILE *fp, uint32_t &nVal)
136
115k
{
137
115k
    const bool bRet = VSIFReadL(&nVal, 1, sizeof(nVal), fp) == sizeof(nVal);
138
115k
    CPL_LSBPTR32(&nVal);
139
115k
    return bRet;
140
115k
}
141
142
/************************************************************************/
143
/*                          WriteUInt32()                               */
144
/************************************************************************/
145
146
inline bool WriteUInt32(VSILFILE *fp, uint32_t nVal)
147
748k
{
148
748k
    CPL_LSBPTR32(&nVal);
149
748k
    return VSIFWriteL(&nVal, 1, sizeof(nVal), fp) == sizeof(nVal);
150
748k
}
151
152
/************************************************************************/
153
/*                          WriteUInt64()                               */
154
/************************************************************************/
155
156
inline bool WriteUInt64(VSILFILE *fp, uint64_t nVal)
157
16.6k
{
158
16.6k
    CPL_LSBPTR64(&nVal);
159
16.6k
    return VSIFWriteL(&nVal, 1, sizeof(nVal), fp) == sizeof(nVal);
160
16.6k
}
161
162
/************************************************************************/
163
/*                          WriteFloat64()                               */
164
/************************************************************************/
165
166
inline bool WriteFloat64(VSILFILE *fp, double dfVal)
167
0
{
168
0
    CPL_LSBPTR64(&dfVal);
169
0
    return VSIFWriteL(&dfVal, 1, sizeof(dfVal), fp) == sizeof(dfVal);
170
0
}
171
172
/************************************************************************/
173
/*                          WriteUInt32()                               */
174
/************************************************************************/
175
176
inline void WriteUInt32(std::vector<GByte> &abyBuffer, uint32_t nVal)
177
36.8k
{
178
36.8k
    CPL_LSBPTR32(&nVal);
179
36.8k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
180
36.8k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
181
36.8k
}
182
183
/************************************************************************/
184
/*                          WriteUInt32()                               */
185
/************************************************************************/
186
187
inline void WriteUInt32(std::vector<GByte> &abyBuffer, uint32_t nVal,
188
                        size_t nPos)
189
2.05k
{
190
2.05k
    CPL_LSBPTR32(&nVal);
191
2.05k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
192
2.05k
    memcpy(&abyBuffer[nPos], pabyInput, sizeof(nVal));
193
2.05k
}
194
195
/************************************************************************/
196
/*                          WriteFloat32()                               */
197
/************************************************************************/
198
199
inline void WriteFloat32(std::vector<GByte> &abyBuffer, float fVal)
200
0
{
201
0
    CPL_LSBPTR32(&fVal);
202
0
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&fVal);
203
0
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(fVal));
204
0
}
205
206
/************************************************************************/
207
/*                          WriteFloat64()                               */
208
/************************************************************************/
209
210
inline void WriteFloat64(std::vector<GByte> &abyBuffer, double dfVal)
211
15.0k
{
212
15.0k
    CPL_LSBPTR64(&dfVal);
213
15.0k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&dfVal);
214
15.0k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(dfVal));
215
15.0k
}
216
217
/************************************************************************/
218
/*                          WriteInt32()                                */
219
/************************************************************************/
220
221
inline void WriteInt32(std::vector<GByte> &abyBuffer, int32_t nVal)
222
6.49k
{
223
6.49k
    CPL_LSBPTR32(&nVal);
224
6.49k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
225
6.49k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
226
6.49k
}
227
228
/************************************************************************/
229
/*                          WriteInt64()                                */
230
/************************************************************************/
231
232
inline void WriteInt64(std::vector<GByte> &abyBuffer, int64_t nVal)
233
0
{
234
0
    CPL_LSBPTR64(&nVal);
235
0
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
236
0
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
237
0
}
238
239
/************************************************************************/
240
/*                          WriteUInt16()                               */
241
/************************************************************************/
242
243
inline void WriteUInt16(std::vector<GByte> &abyBuffer, uint16_t nVal)
244
9.14k
{
245
9.14k
    CPL_LSBPTR16(&nVal);
246
9.14k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
247
9.14k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
248
9.14k
}
249
250
/************************************************************************/
251
/*                          WriteInt16()                                */
252
/************************************************************************/
253
254
inline void WriteInt16(std::vector<GByte> &abyBuffer, int16_t nVal)
255
672
{
256
672
    CPL_LSBPTR16(&nVal);
257
672
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
258
672
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
259
672
}
260
261
/************************************************************************/
262
/*                          WriteUInt8()                                */
263
/************************************************************************/
264
265
inline void WriteUInt8(std::vector<GByte> &abyBuffer, uint8_t nVal)
266
751k
{
267
751k
    abyBuffer.push_back(nVal);
268
751k
}
269
270
/************************************************************************/
271
/*                          WriteUInt64()                               */
272
/************************************************************************/
273
274
inline void WriteUInt64(std::vector<GByte> &abyBuffer, uint64_t nVal)
275
0
{
276
0
    CPL_LSBPTR64(&nVal);
277
0
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
278
0
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
279
0
}
280
281
/************************************************************************/
282
/*                             WriteVarUInt()                           */
283
/************************************************************************/
284
285
inline void WriteVarUInt(std::vector<GByte> &abyBuffer, uint64_t nVal)
286
610k
{
287
624k
    while (true)
288
624k
    {
289
624k
        if (nVal >= 0x80)
290
14.2k
        {
291
14.2k
            WriteUInt8(abyBuffer, static_cast<uint8_t>(0x80 | (nVal & 0x7F)));
292
14.2k
            nVal >>= 7;
293
14.2k
        }
294
610k
        else
295
610k
        {
296
610k
            WriteUInt8(abyBuffer, static_cast<uint8_t>(nVal));
297
610k
            break;
298
610k
        }
299
624k
    }
300
610k
}
301
302
/************************************************************************/
303
/*                             WriteVarInt()                            */
304
/************************************************************************/
305
306
inline void WriteVarInt(std::vector<GByte> &abyBuffer, int64_t nVal)
307
0
{
308
0
    uint64_t nUVal;
309
0
    if (nVal < 0)
310
0
    {
311
0
        if (nVal == std::numeric_limits<int64_t>::min())
312
0
            nUVal = static_cast<uint64_t>(1) << 63;
313
0
        else
314
0
            nUVal = -nVal;
315
0
        if (nUVal >= 0x40)
316
0
        {
317
0
            WriteUInt8(abyBuffer,
318
0
                       static_cast<uint8_t>(0x80 | 0x40 | (nUVal & 0x3F)));
319
0
            nUVal >>= 6;
320
0
        }
321
0
        else
322
0
        {
323
0
            WriteUInt8(abyBuffer, static_cast<uint8_t>(0x40 | (nUVal & 0x3F)));
324
0
            return;
325
0
        }
326
0
    }
327
0
    else
328
0
    {
329
0
        nUVal = nVal;
330
0
        if (nUVal >= 0x40)
331
0
        {
332
0
            WriteUInt8(abyBuffer, static_cast<uint8_t>(0x80 | (nUVal & 0x3F)));
333
0
            nUVal >>= 6;
334
0
        }
335
0
        else
336
0
        {
337
0
            WriteUInt8(abyBuffer, static_cast<uint8_t>((nUVal & 0x3F)));
338
0
            return;
339
0
        }
340
0
    }
341
342
0
    WriteVarUInt(abyBuffer, nUVal);
343
0
}
344
345
/************************************************************************/
346
/*                            ReadUTF16String()                         */
347
/************************************************************************/
348
349
inline std::string ReadUTF16String(const GByte *pabyIter, int nCarCount)
350
1.02M
{
351
1.02M
    std::wstring osWideStr;
352
9.21M
    for (int j = 0; j < nCarCount; j++)
353
8.18M
        osWideStr += pabyIter[2 * j] | (pabyIter[2 * j + 1] << 8);
354
1.02M
    char *pszStr =
355
1.02M
        CPLRecodeFromWChar(osWideStr.c_str(), CPL_ENC_UCS2, CPL_ENC_UTF8);
356
1.02M
    std::string osRet(pszStr);
357
1.02M
    CPLFree(pszStr);
358
1.02M
    return osRet;
359
1.02M
}
360
361
/************************************************************************/
362
/*                           WriteUTF16String()                         */
363
/************************************************************************/
364
365
enum UTF16StringFormat
366
{
367
    NUMBER_OF_BYTES_ON_UINT16,
368
    NUMBER_OF_BYTES_ON_VARUINT,
369
    NUMBER_OF_CHARS_ON_UINT8,
370
    NUMBER_OF_CHARS_ON_UINT32,
371
};
372
373
inline void WriteUTF16String(std::vector<GByte> &abyBuffer, const char *pszStr,
374
                             UTF16StringFormat eFormat)
375
54.6k
{
376
54.6k
    wchar_t *pszWStr = CPLRecodeToWChar(pszStr, CPL_ENC_UTF8, CPL_ENC_UCS2);
377
54.6k
    size_t nWLen = wcslen(pszWStr);
378
54.6k
    switch (eFormat)
379
54.6k
    {
380
885
        case NUMBER_OF_BYTES_ON_UINT16:
381
885
        {
382
            // Write length as bytes
383
885
            const auto nLenToWrite =
384
885
                std::min(static_cast<size_t>(65534), sizeof(uint16_t) * nWLen);
385
885
            if (nLenToWrite < sizeof(uint16_t) * nWLen)
386
0
            {
387
0
                CPLError(CE_Warning, CPLE_AppDefined,
388
0
                         "String %s truncated to %u bytes", pszStr,
389
0
                         static_cast<uint32_t>(nLenToWrite));
390
0
                nWLen = nLenToWrite / sizeof(uint16_t);
391
0
            }
392
885
            WriteUInt16(abyBuffer, static_cast<uint16_t>(nLenToWrite));
393
885
            break;
394
0
        }
395
396
0
        case NUMBER_OF_BYTES_ON_VARUINT:
397
0
        {
398
            // Write length as bytes
399
0
            WriteVarUInt(abyBuffer, sizeof(uint16_t) * nWLen);
400
0
            break;
401
0
        }
402
403
49.5k
        case NUMBER_OF_CHARS_ON_UINT8:
404
49.5k
        {
405
            // Write length as number of UTF16 characters
406
49.5k
            const auto nLenToWrite = std::min(static_cast<size_t>(255), nWLen);
407
49.5k
            if (nLenToWrite < nWLen)
408
1
            {
409
1
                CPLError(CE_Warning, CPLE_AppDefined,
410
1
                         "String %s truncated to %u UTF16 characters", pszStr,
411
1
                         static_cast<uint32_t>(nLenToWrite));
412
1
                nWLen = nLenToWrite;
413
1
            }
414
49.5k
            WriteUInt8(abyBuffer, static_cast<uint8_t>(nLenToWrite));
415
49.5k
            break;
416
0
        }
417
418
4.13k
        case NUMBER_OF_CHARS_ON_UINT32:
419
4.13k
        {
420
            // Write length as number of UTF16 characters
421
4.13k
            WriteUInt32(abyBuffer, static_cast<uint32_t>(nWLen));
422
4.13k
            break;
423
0
        }
424
54.6k
    }
425
426
54.6k
    if (nWLen)
427
29.8k
    {
428
29.8k
        std::vector<uint16_t> anChars(nWLen);
429
367k
        for (size_t i = 0; i < nWLen; ++i)
430
337k
        {
431
337k
            anChars[i] = static_cast<uint16_t>(pszWStr[i]);
432
337k
            CPL_LSBPTR16(&anChars[i]);
433
337k
        }
434
29.8k
        const GByte *pabyInput =
435
29.8k
            reinterpret_cast<const GByte *>(anChars.data());
436
29.8k
        abyBuffer.insert(abyBuffer.end(), pabyInput,
437
29.8k
                         pabyInput + nWLen * sizeof(uint16_t));
438
29.8k
    }
439
54.6k
    CPLFree(pszWStr);
440
54.6k
}
441
442
/************************************************************************/
443
/*                      FileGDBOGRDateToDoubleDate()                    */
444
/************************************************************************/
445
446
inline double FileGDBOGRDateToDoubleDate(const OGRField *psField,
447
                                         bool bConvertToGMT,
448
                                         bool bHighPrecision)
449
0
{
450
0
    struct tm brokendowntime;
451
0
    brokendowntime.tm_year = psField->Date.Year - 1900;
452
0
    brokendowntime.tm_mon = psField->Date.Month - 1;
453
0
    brokendowntime.tm_mday = psField->Date.Day;
454
0
    brokendowntime.tm_hour = psField->Date.Hour;
455
0
    brokendowntime.tm_min = psField->Date.Minute;
456
0
    brokendowntime.tm_sec = bHighPrecision
457
0
                                ? static_cast<int>(psField->Date.Second)
458
0
                                : static_cast<int>(psField->Date.Second + 0.5);
459
0
    GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
460
0
    if (bConvertToGMT && psField->Date.TZFlag > 1 &&
461
0
        psField->Date.TZFlag != 100)
462
0
    {
463
        // Convert to GMT
464
0
        const int TZOffset = std::abs(psField->Date.TZFlag - 100) * 15;
465
0
        const int TZHour = TZOffset / 60;
466
0
        const int TZMinute = TZOffset - TZHour * 60;
467
0
        const int nOffset = TZHour * 3600 + TZMinute * 60;
468
0
        if (psField->Date.TZFlag >= 100)
469
0
            nUnixTime -= nOffset;
470
0
        else
471
0
            nUnixTime += nOffset;
472
0
    }
473
    // 25569: Number of days between 1899/12/30 00:00:00 and 1970/01/01 00:00:00
474
0
    return static_cast<double>(
475
0
               nUnixTime +
476
0
               (bHighPrecision
477
0
                    ? fmod(static_cast<double>(psField->Date.Second), 1.0)
478
0
                    : 0)) /
479
0
               3600.0 / 24.0 +
480
0
           25569.0;
481
0
}
482
483
/************************************************************************/
484
/*                      FileGDBOGRTimeToDoubleTime()                    */
485
/************************************************************************/
486
487
inline double FileGDBOGRTimeToDoubleTime(const OGRField *psField)
488
0
{
489
0
    return static_cast<double>(psField->Date.Hour * 3600 +
490
0
                               psField->Date.Minute * 60 +
491
0
                               psField->Date.Second) /
492
0
           3600.0 / 24.0;
493
0
}
494
495
void FileGDBTablePrintError(const char *pszFile, int nLineNumber);
496
497
2.27M
#define PrintError() FileGDBTablePrintError(__FILE__, __LINE__)
498
499
/************************************************************************/
500
/*                          returnError()                               */
501
/************************************************************************/
502
503
#define returnError()                                                          \
504
2.27M
    do                                                                         \
505
2.27M
    {                                                                          \
506
2.27M
        PrintError();                                                          \
507
2.27M
        return (errorRetValue);                                                \
508
2.27M
    } while (0)
509
510
/************************************************************************/
511
/*                         returnErrorIf()                              */
512
/************************************************************************/
513
514
#define returnErrorIf(expr)                                                    \
515
22.9M
    do                                                                         \
516
22.9M
    {                                                                          \
517
22.9M
        if ((expr))                                                            \
518
22.9M
            returnError();                                                     \
519
22.9M
    } while (0)
520
521
/************************************************************************/
522
/*                       returnErrorAndCleanupIf()                      */
523
/************************************************************************/
524
525
#define returnErrorAndCleanupIf(expr, cleanup)                                 \
526
7.99M
    do                                                                         \
527
7.99M
    {                                                                          \
528
9.04M
        if ((expr))                                                            \
529
7.99M
        {                                                                      \
530
1.60M
            cleanup;                                                           \
531
1.60M
            returnError();                                                     \
532
1.60M
        }                                                                      \
533
7.99M
    } while (0)
534
535
} /* namespace OpenFileGDB */
536
537
#endif /* FILEGDBTABLE_PRIV_H_INCLUDED */