Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/openfilegdb/filegdbtable_priv.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_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
788k
#define DIV_ROUND_UP(a, b) (((a) % (b)) == 0 ? ((a) / (b)) : (((a) / (b)) + 1))
28
29
13.6M
#define TEST_BIT(ar, bit) (ar[(bit) / 8] & (1 << ((bit) % 8)))
30
173k
#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
25.0k
{
41
25.0k
    GInt16 nVal;
42
25.0k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
43
25.0k
    CPL_LSBPTR16(&nVal);
44
25.0k
    return nVal;
45
25.0k
}
46
47
/************************************************************************/
48
/*                              GetUInt16()                             */
49
/************************************************************************/
50
51
inline GUInt16 GetUInt16(const GByte *pBaseAddr, int iOffset)
52
162k
{
53
162k
    GUInt16 nVal;
54
162k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
55
162k
    CPL_LSBPTR16(&nVal);
56
162k
    return nVal;
57
162k
}
58
59
/************************************************************************/
60
/*                              GetInt32()                              */
61
/************************************************************************/
62
63
inline GInt32 GetInt32(const GByte *pBaseAddr, int iOffset)
64
846k
{
65
846k
    GInt32 nVal;
66
846k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
67
846k
    CPL_LSBPTR32(&nVal);
68
846k
    return nVal;
69
846k
}
70
71
/************************************************************************/
72
/*                              GetUInt32()                             */
73
/************************************************************************/
74
75
inline GUInt32 GetUInt32(const GByte *pBaseAddr, int iOffset)
76
71.2M
{
77
71.2M
    GUInt32 nVal;
78
71.2M
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
79
71.2M
    CPL_LSBPTR32(&nVal);
80
71.2M
    return nVal;
81
71.2M
}
82
83
/************************************************************************/
84
/*                              GetInt64()                              */
85
/************************************************************************/
86
87
inline int64_t GetInt64(const GByte *pBaseAddr, int iOffset)
88
1.22k
{
89
1.22k
    int64_t nVal;
90
1.22k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
91
1.22k
    CPL_LSBPTR64(&nVal);
92
1.22k
    return nVal;
93
1.22k
}
94
95
/************************************************************************/
96
/*                              GetUInt64()                             */
97
/************************************************************************/
98
99
inline uint64_t GetUInt64(const GByte *pBaseAddr, int iOffset)
100
98.5k
{
101
98.5k
    uint64_t nVal;
102
98.5k
    memcpy(&nVal, pBaseAddr + sizeof(nVal) * iOffset, sizeof(nVal));
103
98.5k
    CPL_LSBPTR64(&nVal);
104
98.5k
    return nVal;
105
98.5k
}
106
107
/************************************************************************/
108
/*                             GetFloat32()                             */
109
/************************************************************************/
110
111
inline float GetFloat32(const GByte *pBaseAddr, int iOffset)
112
13.8k
{
113
13.8k
    float fVal;
114
13.8k
    memcpy(&fVal, pBaseAddr + sizeof(fVal) * iOffset, sizeof(fVal));
115
13.8k
    CPL_LSBPTR32(&fVal);
116
13.8k
    return fVal;
117
13.8k
}
118
119
/************************************************************************/
120
/*                             GetFloat64()                             */
121
/************************************************************************/
122
123
inline double GetFloat64(const GByte *pBaseAddr, int iOffset)
124
1.30M
{
125
1.30M
    double dfVal;
126
1.30M
    memcpy(&dfVal, pBaseAddr + sizeof(dfVal) * iOffset, sizeof(dfVal));
127
1.30M
    CPL_LSBPTR64(&dfVal);
128
1.30M
    return dfVal;
129
1.30M
}
130
131
/************************************************************************/
132
/*                          ReadUInt32()                                */
133
/************************************************************************/
134
135
inline bool ReadUInt32(VSILFILE *fp, uint32_t &nVal)
136
31.9k
{
137
31.9k
    const bool bRet = VSIFReadL(&nVal, 1, sizeof(nVal), fp) == sizeof(nVal);
138
31.9k
    CPL_LSBPTR32(&nVal);
139
31.9k
    return bRet;
140
31.9k
}
141
142
/************************************************************************/
143
/*                          WriteUInt32()                               */
144
/************************************************************************/
145
146
inline bool WriteUInt32(VSILFILE *fp, uint32_t nVal)
147
1.13M
{
148
1.13M
    CPL_LSBPTR32(&nVal);
149
1.13M
    return VSIFWriteL(&nVal, 1, sizeof(nVal), fp) == sizeof(nVal);
150
1.13M
}
151
152
/************************************************************************/
153
/*                          WriteUInt64()                               */
154
/************************************************************************/
155
156
inline bool WriteUInt64(VSILFILE *fp, uint64_t nVal)
157
109k
{
158
109k
    CPL_LSBPTR64(&nVal);
159
109k
    return VSIFWriteL(&nVal, 1, sizeof(nVal), fp) == sizeof(nVal);
160
109k
}
161
162
/************************************************************************/
163
/*                          WriteFloat64()                               */
164
/************************************************************************/
165
166
inline bool WriteFloat64(VSILFILE *fp, double dfVal)
167
282
{
168
282
    CPL_LSBPTR64(&dfVal);
169
282
    return VSIFWriteL(&dfVal, 1, sizeof(dfVal), fp) == sizeof(dfVal);
170
282
}
171
172
/************************************************************************/
173
/*                          WriteUInt32()                               */
174
/************************************************************************/
175
176
inline void WriteUInt32(std::vector<GByte> &abyBuffer, uint32_t nVal)
177
233k
{
178
233k
    CPL_LSBPTR32(&nVal);
179
233k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
180
233k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
181
233k
}
182
183
/************************************************************************/
184
/*                          WriteUInt32()                               */
185
/************************************************************************/
186
187
inline void WriteUInt32(std::vector<GByte> &abyBuffer, uint32_t nVal,
188
                        size_t nPos)
189
21.9k
{
190
21.9k
    CPL_LSBPTR32(&nVal);
191
21.9k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
192
21.9k
    memcpy(&abyBuffer[nPos], pabyInput, sizeof(nVal));
193
21.9k
}
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
64.7k
{
212
64.7k
    CPL_LSBPTR64(&dfVal);
213
64.7k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&dfVal);
214
64.7k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(dfVal));
215
64.7k
}
216
217
/************************************************************************/
218
/*                          WriteInt32()                                */
219
/************************************************************************/
220
221
inline void WriteInt32(std::vector<GByte> &abyBuffer, int32_t nVal)
222
26.2k
{
223
26.2k
    CPL_LSBPTR32(&nVal);
224
26.2k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
225
26.2k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
226
26.2k
}
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
46.9k
{
245
46.9k
    CPL_LSBPTR16(&nVal);
246
46.9k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
247
46.9k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
248
46.9k
}
249
250
/************************************************************************/
251
/*                          WriteInt16()                                */
252
/************************************************************************/
253
254
inline void WriteInt16(std::vector<GByte> &abyBuffer, int16_t nVal)
255
9.84k
{
256
9.84k
    CPL_LSBPTR16(&nVal);
257
9.84k
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
258
9.84k
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
259
9.84k
}
260
261
/************************************************************************/
262
/*                          WriteUInt8()                                */
263
/************************************************************************/
264
265
inline void WriteUInt8(std::vector<GByte> &abyBuffer, uint8_t nVal)
266
1.77M
{
267
1.77M
    abyBuffer.push_back(nVal);
268
1.77M
}
269
270
/************************************************************************/
271
/*                          WriteUInt64()                               */
272
/************************************************************************/
273
274
inline void WriteUInt64(std::vector<GByte> &abyBuffer, uint64_t nVal)
275
125
{
276
125
    CPL_LSBPTR64(&nVal);
277
125
    const GByte *pabyInput = reinterpret_cast<const GByte *>(&nVal);
278
125
    abyBuffer.insert(abyBuffer.end(), pabyInput, pabyInput + sizeof(nVal));
279
125
}
280
281
/************************************************************************/
282
/*                             WriteVarUInt()                           */
283
/************************************************************************/
284
285
inline void WriteVarUInt(std::vector<GByte> &abyBuffer, uint64_t nVal)
286
864k
{
287
881k
    while (true)
288
881k
    {
289
881k
        if (nVal >= 0x80)
290
16.4k
        {
291
16.4k
            WriteUInt8(abyBuffer, static_cast<uint8_t>(0x80 | (nVal & 0x7F)));
292
16.4k
            nVal >>= 7;
293
16.4k
        }
294
864k
        else
295
864k
        {
296
864k
            WriteUInt8(abyBuffer, static_cast<uint8_t>(nVal));
297
864k
            break;
298
864k
        }
299
881k
    }
300
864k
}
301
302
/************************************************************************/
303
/*                             WriteVarInt()                            */
304
/************************************************************************/
305
306
inline void WriteVarInt(std::vector<GByte> &abyBuffer, int64_t nVal)
307
625
{
308
625
    uint64_t nUVal;
309
625
    if (nVal < 0)
310
47
    {
311
47
        if (nVal == std::numeric_limits<int64_t>::min())
312
0
            nUVal = static_cast<uint64_t>(1) << 63;
313
47
        else
314
47
            nUVal = -nVal;
315
47
        if (nUVal >= 0x40)
316
47
        {
317
47
            WriteUInt8(abyBuffer,
318
47
                       static_cast<uint8_t>(0x80 | 0x40 | (nUVal & 0x3F)));
319
47
            nUVal >>= 6;
320
47
        }
321
0
        else
322
0
        {
323
0
            WriteUInt8(abyBuffer, static_cast<uint8_t>(0x40 | (nUVal & 0x3F)));
324
0
            return;
325
0
        }
326
47
    }
327
578
    else
328
578
    {
329
578
        nUVal = nVal;
330
578
        if (nUVal >= 0x40)
331
328
        {
332
328
            WriteUInt8(abyBuffer, static_cast<uint8_t>(0x80 | (nUVal & 0x3F)));
333
328
            nUVal >>= 6;
334
328
        }
335
250
        else
336
250
        {
337
250
            WriteUInt8(abyBuffer, static_cast<uint8_t>((nUVal & 0x3F)));
338
250
            return;
339
250
        }
340
578
    }
341
342
375
    WriteVarUInt(abyBuffer, nUVal);
343
375
}
344
345
/************************************************************************/
346
/*                            ReadUTF16String()                         */
347
/************************************************************************/
348
349
inline std::string ReadUTF16String(const GByte *pabyIter, int nCarCount)
350
2.49M
{
351
2.49M
    std::wstring osWideStr;
352
22.1M
    for (int j = 0; j < nCarCount; j++)
353
19.6M
        osWideStr += pabyIter[2 * j] | (pabyIter[2 * j + 1] << 8);
354
2.49M
    char *pszStr =
355
2.49M
        CPLRecodeFromWChar(osWideStr.c_str(), CPL_ENC_UCS2, CPL_ENC_UTF8);
356
2.49M
    std::string osRet(pszStr);
357
2.49M
    CPLFree(pszStr);
358
2.49M
    return osRet;
359
2.49M
}
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
367k
{
376
367k
    wchar_t *pszWStr = CPLRecodeToWChar(pszStr, CPL_ENC_UTF8, CPL_ENC_UCS2);
377
367k
    size_t nWLen = wcslen(pszWStr);
378
367k
    switch (eFormat)
379
367k
    {
380
3.19k
        case NUMBER_OF_BYTES_ON_UINT16:
381
3.19k
        {
382
            // Write length as bytes
383
3.19k
            const auto nLenToWrite =
384
3.19k
                std::min(static_cast<size_t>(65534), sizeof(uint16_t) * nWLen);
385
3.19k
            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
3.19k
            WriteUInt16(abyBuffer, static_cast<uint16_t>(nLenToWrite));
393
3.19k
            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
349k
        case NUMBER_OF_CHARS_ON_UINT8:
404
349k
        {
405
            // Write length as number of UTF16 characters
406
349k
            const auto nLenToWrite = std::min(static_cast<size_t>(255), nWLen);
407
349k
            if (nLenToWrite < nWLen)
408
18
            {
409
18
                CPLError(CE_Warning, CPLE_AppDefined,
410
18
                         "String %s truncated to %u UTF16 characters", pszStr,
411
18
                         static_cast<uint32_t>(nLenToWrite));
412
18
                nWLen = nLenToWrite;
413
18
            }
414
349k
            WriteUInt8(abyBuffer, static_cast<uint8_t>(nLenToWrite));
415
349k
            break;
416
0
        }
417
418
14.5k
        case NUMBER_OF_CHARS_ON_UINT32:
419
14.5k
        {
420
            // Write length as number of UTF16 characters
421
14.5k
            WriteUInt32(abyBuffer, static_cast<uint32_t>(nWLen));
422
14.5k
            break;
423
0
        }
424
367k
    }
425
426
367k
    if (nWLen)
427
192k
    {
428
192k
        std::vector<uint16_t> anChars(nWLen);
429
2.52M
        for (size_t i = 0; i < nWLen; ++i)
430
2.32M
        {
431
2.32M
            anChars[i] = static_cast<uint16_t>(pszWStr[i]);
432
2.32M
            CPL_LSBPTR16(&anChars[i]);
433
2.32M
        }
434
192k
        const GByte *pabyInput =
435
192k
            reinterpret_cast<const GByte *>(anChars.data());
436
192k
        abyBuffer.insert(abyBuffer.end(), pabyInput,
437
192k
                         pabyInput + nWLen * sizeof(uint16_t));
438
192k
    }
439
367k
    CPLFree(pszWStr);
440
367k
}
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.12M
#define PrintError() FileGDBTablePrintError(__FILE__, __LINE__)
498
499
/************************************************************************/
500
/*                          returnError()                               */
501
/************************************************************************/
502
503
#define returnError()                                                          \
504
2.12M
    do                                                                         \
505
2.12M
    {                                                                          \
506
2.12M
        PrintError();                                                          \
507
2.12M
        return (errorRetValue);                                                \
508
2.12M
    } while (0)
509
510
/************************************************************************/
511
/*                         returnErrorIf()                              */
512
/************************************************************************/
513
514
#define returnErrorIf(expr)                                                    \
515
29.0M
    do                                                                         \
516
29.0M
    {                                                                          \
517
29.0M
        if ((expr))                                                            \
518
29.0M
            returnError();                                                     \
519
29.0M
    } while (0)
520
521
/************************************************************************/
522
/*                       returnErrorAndCleanupIf()                      */
523
/************************************************************************/
524
525
#define returnErrorAndCleanupIf(expr, cleanup)                                 \
526
8.54M
    do                                                                         \
527
8.54M
    {                                                                          \
528
10.1M
        if ((expr))                                                            \
529
8.54M
        {                                                                      \
530
1.44M
            cleanup;                                                           \
531
1.44M
            returnError();                                                     \
532
1.44M
        }                                                                      \
533
8.54M
    } while (0)
534
535
} /* namespace OpenFileGDB */
536
537
#endif /* FILEGDBTABLE_PRIV_H_INCLUDED */