Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/osm/gpb.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
5
 * Purpose:  Google Protocol Buffer generic handling functions
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#ifndef GPB_H_INCLUDED
14
#define GPB_H_INCLUDED
15
16
#include "cpl_port.h"
17
#include "cpl_error.h"
18
#include "cpl_string.h"
19
20
#include <string>
21
#include <exception>
22
23
#ifndef CHECK_OOB
24
75.8M
#define CHECK_OOB 1
25
#endif
26
27
#if defined(__clang__)
28
#pragma clang diagnostic push
29
#pragma clang diagnostic ignored "-Wweak-vtables"
30
#endif
31
32
class GPBException final : public std::exception
33
{
34
    std::string m_osMessage;
35
36
  public:
37
    explicit GPBException(int nLine)
38
201k
        : m_osMessage(CPLSPrintf("Parsing error occurred at line %d", nLine))
39
201k
    {
40
201k
    }
41
42
    const char *what() const noexcept override
43
131k
    {
44
131k
        return m_osMessage.c_str();
45
131k
    }
46
};
47
48
#if defined(__clang__)
49
#pragma clang diagnostic pop
50
#endif
51
52
201k
#define THROW_GPB_EXCEPTION throw GPBException(__LINE__)
53
54
/************************************************************************/
55
/*                  Google Protocol Buffer definitions                  */
56
/************************************************************************/
57
58
// TODO(schwehr): This should be an enum.
59
constexpr int WT_VARINT = 0;
60
constexpr int WT_64BIT = 1;
61
constexpr int WT_DATA = 2;
62
// constexpr WT_STARTGROUP = 3; // unused
63
// constexpr WT_ENDGROUP = 4; // unused
64
constexpr int WT_32BIT = 5;
65
66
28.6M
#define MAKE_KEY(nFieldNumber, nWireType) ((nFieldNumber << 3) | nWireType)
67
14.7M
#define GET_WIRETYPE(nKey) (nKey & 0x7)
68
585k
#define GET_FIELDNUMBER(nKey) (nKey >> 3)
69
70
/************************************************************************/
71
/*                           ReadVarUInt32()                            */
72
/************************************************************************/
73
74
inline int ReadVarUInt32(const GByte **ppabyData)
75
4.92M
{
76
4.92M
    unsigned int nVal = 0;
77
4.92M
    int nShift = 0;
78
4.92M
    const GByte *pabyData = *ppabyData;
79
80
5.58M
    while (true)
81
5.58M
    {
82
5.58M
        int nByte = *pabyData;
83
5.58M
        if (!(nByte & 0x80))
84
4.79M
        {
85
4.79M
            *ppabyData = pabyData + 1;
86
4.79M
            return nVal | (static_cast<unsigned>(nByte) << nShift);
87
4.79M
        }
88
794k
        nVal |= (nByte & 0x7f) << nShift;
89
794k
        pabyData++;
90
794k
        nShift += 7;
91
794k
        if (nShift == 28)
92
135k
        {
93
135k
            nByte = *pabyData;
94
135k
            if (!(nByte & 0x80))
95
75.5k
            {
96
75.5k
                *ppabyData = pabyData + 1;
97
75.5k
                return nVal | ((static_cast<unsigned>(nByte) & 0xf) << nShift);
98
75.5k
            }
99
59.6k
            *ppabyData = pabyData;
100
59.6k
            return nVal;
101
135k
        }
102
794k
    }
103
4.92M
}
104
105
#define READ_VARUINT32(pabyData, pabyDataLimit, nVal)                          \
106
4.92M
    {                                                                          \
107
4.92M
        nVal = ReadVarUInt32(&pabyData);                                       \
108
4.92M
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
109
4.92M
            THROW_GPB_EXCEPTION;                                               \
110
4.92M
    }
111
112
#define READ_SIZE(pabyData, pabyDataLimit, nSize)                              \
113
2.75M
    {                                                                          \
114
2.75M
        READ_VARUINT32(pabyData, pabyDataLimit, nSize);                        \
115
2.74M
        if (CHECK_OOB &&                                                       \
116
2.74M
            nSize > static_cast<unsigned int>(pabyDataLimit - pabyData))       \
117
2.74M
            THROW_GPB_EXCEPTION;                                               \
118
2.74M
    }
119
120
/************************************************************************/
121
/*                           ReadVarUInt64()                            */
122
/************************************************************************/
123
124
inline GUIntBig ReadVarUInt64(const GByte **ppabyData)
125
16.0M
{
126
16.0M
    GUIntBig nVal = 0;
127
16.0M
    int nShift = 0;
128
16.0M
    const GByte *pabyData = *ppabyData;
129
130
25.3M
    while (true)
131
25.3M
    {
132
25.3M
        int nByte = *pabyData;
133
25.3M
        if (!(nByte & 0x80))
134
15.3M
        {
135
15.3M
            *ppabyData = pabyData + 1;
136
15.3M
            return nVal | (static_cast<GUIntBig>(nByte) << nShift);
137
15.3M
        }
138
9.98M
        nVal |= (static_cast<GUIntBig>(nByte & 0x7f)) << nShift;
139
9.98M
        pabyData++;
140
9.98M
        nShift += 7;
141
9.98M
        if (nShift == 63)
142
758k
        {
143
758k
            nByte = *pabyData;
144
758k
            if (!(nByte & 0x80))
145
54.4k
            {
146
54.4k
                *ppabyData = pabyData + 1;
147
54.4k
                return nVal | ((static_cast<GUIntBig>(nByte) & 1) << nShift);
148
54.4k
            }
149
703k
            *ppabyData = pabyData;
150
703k
            return nVal;
151
758k
        }
152
9.98M
    }
153
16.0M
}
154
155
#define READ_VARUINT64(pabyData, pabyDataLimit, nVal)                          \
156
6.51k
    {                                                                          \
157
6.51k
        nVal = ReadVarUInt64(&pabyData);                                       \
158
6.51k
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
159
6.51k
            THROW_GPB_EXCEPTION;                                               \
160
6.51k
    }
161
162
#define READ_SIZE64(pabyData, pabyDataLimit, nSize)                            \
163
    {                                                                          \
164
        READ_VARUINT64(pabyData, pabyDataLimit, nSize);                        \
165
        if (CHECK_OOB &&                                                       \
166
            nSize > static_cast<unsigned int>(pabyDataLimit - pabyData))       \
167
            THROW_GPB_EXCEPTION;                                               \
168
    }
169
170
/************************************************************************/
171
/*                            ReadVarInt64()                            */
172
/************************************************************************/
173
174
inline GIntBig ReadVarInt64(const GByte **ppabyData)
175
26.0k
{
176
26.0k
    return static_cast<GIntBig>(ReadVarUInt64(ppabyData));
177
26.0k
}
178
179
#define READ_VARINT64(pabyData, pabyDataLimit, nVal)                           \
180
26.0k
    {                                                                          \
181
26.0k
        nVal = ReadVarInt64(&pabyData);                                        \
182
26.0k
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
183
26.0k
            THROW_GPB_EXCEPTION;                                               \
184
26.0k
    }
185
186
/************************************************************************/
187
/*                             DecodeSInt()                             */
188
/************************************************************************/
189
190
inline GIntBig DecodeSInt(GUIntBig nVal)
191
27.6k
{
192
27.6k
    return ((nVal & 1) == 0) ? static_cast<GIntBig>(nVal >> 1)
193
27.6k
                             : -static_cast<GIntBig>(nVal >> 1) - 1;
194
27.6k
}
195
196
inline GInt32 DecodeSInt(GUInt32 nVal)
197
798k
{
198
798k
    return ((nVal & 1) == 0) ? static_cast<GInt32>(nVal >> 1)
199
798k
                             : -static_cast<GInt32>(nVal >> 1) - 1;
200
798k
}
201
202
/************************************************************************/
203
/*                           ReadVarSInt64()                            */
204
/************************************************************************/
205
206
inline GIntBig ReadVarSInt64(const GByte **ppabyPtr)
207
27.6k
{
208
27.6k
    return DecodeSInt(ReadVarUInt64(ppabyPtr));
209
27.6k
}
210
211
#define READ_VARSINT64(pabyData, pabyDataLimit, nVal)                          \
212
22.6k
    {                                                                          \
213
22.6k
        nVal = ReadVarSInt64(&pabyData);                                       \
214
22.6k
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
215
22.6k
            THROW_GPB_EXCEPTION;                                               \
216
22.6k
    }
217
218
#define READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nVal)                  \
219
3.82k
    {                                                                          \
220
3.82k
        nVal = ReadVarSInt64(&pabyData);                                       \
221
3.82k
    }
222
223
/************************************************************************/
224
/*                            ReadVarInt32()                            */
225
/************************************************************************/
226
227
inline int ReadVarInt32(const GByte **ppabyData)
228
15.2M
{
229
    /*  If you use int32 or int64 as the type for a negative number, */
230
    /* the resulting varint is always ten bytes long */
231
15.2M
    GIntBig nVal = static_cast<GIntBig>(ReadVarUInt64(ppabyData));
232
15.2M
    return static_cast<int>(nVal);
233
15.2M
}
234
235
#define READ_VARINT32(pabyData, pabyDataLimit, nVal)                           \
236
15.2M
    {                                                                          \
237
15.2M
        nVal = ReadVarInt32(&pabyData);                                        \
238
15.2M
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
239
15.2M
            THROW_GPB_EXCEPTION;                                               \
240
15.2M
    }
241
242
#define READ_VARSINT32(pabyData, pabyDataLimit, nVal)                          \
243
798k
    {                                                                          \
244
798k
        nVal = DecodeSInt(static_cast<GUInt32>(ReadVarUInt64(&pabyData)));     \
245
798k
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
246
798k
            THROW_GPB_EXCEPTION;                                               \
247
798k
    }
248
249
/************************************************************************/
250
/*                            ReadFloat32()                             */
251
/************************************************************************/
252
253
inline float ReadFloat32(const GByte **ppabyData, const GByte *pabyDataLimit)
254
798
{
255
798
    if (*ppabyData + sizeof(float) > pabyDataLimit)
256
0
        THROW_GPB_EXCEPTION;
257
798
    float fValue;
258
798
    memcpy(&fValue, *ppabyData, sizeof(float));
259
798
    CPL_LSBPTR32(&fValue);
260
798
    *ppabyData += sizeof(float);
261
798
    return fValue;
262
798
}
263
264
/************************************************************************/
265
/*                            ReadFloat64()                             */
266
/************************************************************************/
267
268
inline double ReadFloat64(const GByte **ppabyData, const GByte *pabyDataLimit)
269
176
{
270
176
    if (*ppabyData + sizeof(double) > pabyDataLimit)
271
25
        THROW_GPB_EXCEPTION;
272
151
    double dfValue;
273
151
    memcpy(&dfValue, *ppabyData, sizeof(double));
274
151
    CPL_LSBPTR64(&dfValue);
275
151
    *ppabyData += sizeof(double);
276
151
    return dfValue;
277
176
}
278
279
/************************************************************************/
280
/*                             SkipVarInt()                             */
281
/************************************************************************/
282
283
inline void SkipVarInt(const GByte **ppabyData)
284
12.9M
{
285
12.9M
    const GByte *pabyData = *ppabyData;
286
18.4M
    while (true)
287
18.4M
    {
288
18.4M
        int nByte = *pabyData;
289
18.4M
        if (!(nByte & 0x80))
290
12.9M
        {
291
12.9M
            *ppabyData = pabyData + 1;
292
12.9M
            return;
293
12.9M
        }
294
5.56M
        pabyData++;
295
5.56M
    }
296
12.9M
}
297
298
#define SKIP_VARINT(pabyData, pabyDataLimit)                                   \
299
12.9M
    {                                                                          \
300
12.9M
        SkipVarInt(&pabyData);                                                 \
301
12.9M
        if (CHECK_OOB && pabyData > pabyDataLimit)                             \
302
12.9M
            THROW_GPB_EXCEPTION;                                               \
303
12.9M
    }
304
305
13.4M
#define READ_FIELD_KEY(nKey) READ_VARINT32(pabyData, pabyDataLimit, nKey)
306
307
#define READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength)    \
308
359k
    do                                                                         \
309
359k
    {                                                                          \
310
359k
        READ_SIZE(pabyData, pabyDataLimit, l_nDataLength);                     \
311
350k
        pszTxt = static_cast<char *>(VSI_MALLOC_VERBOSE(l_nDataLength + 1));   \
312
350k
        if (pszTxt == nullptr)                                                 \
313
350k
            THROW_GPB_EXCEPTION;                                               \
314
350k
        memcpy(pszTxt, pabyData, l_nDataLength);                               \
315
350k
        pszTxt[l_nDataLength] = 0;                                             \
316
350k
        pabyData += l_nDataLength;                                             \
317
350k
    } while (0)
318
319
#define READ_TEXT(pabyData, pabyDataLimit, pszTxt)                             \
320
347k
    do                                                                         \
321
347k
    {                                                                          \
322
347k
        unsigned int l_nDataLength;                                            \
323
347k
        READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength);   \
324
347k
    } while (0)
325
326
/************************************************************************/
327
/*                          SkipUnknownField()                          */
328
/************************************************************************/
329
330
#define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose)            \
331
14.4M
    int nWireType = GET_WIRETYPE(nKey);                                        \
332
14.4M
    if (verbose)                                                               \
333
14.4M
    {                                                                          \
334
97
        int nFieldNumber = GET_FIELDNUMBER(nKey);                              \
335
97
        CPLDebug("PBF", "Unhandled case: nFieldNumber = %d, nWireType = %d",   \
336
97
                 nFieldNumber, nWireType);                                     \
337
97
    }                                                                          \
338
14.4M
    switch (nWireType)                                                         \
339
14.4M
    {                                                                          \
340
11.7M
        case WT_VARINT:                                                        \
341
11.7M
        {                                                                      \
342
11.7M
            SKIP_VARINT(pabyData, pabyDataLimit);                              \
343
11.7M
            break;                                                             \
344
11.7M
        }                                                                      \
345
11.7M
        case WT_64BIT:                                                         \
346
213k
        {                                                                      \
347
213k
            if (CHECK_OOB && pabyDataLimit - pabyData < 8)                     \
348
213k
                THROW_GPB_EXCEPTION;                                           \
349
213k
            pabyData += 8;                                                     \
350
210k
            break;                                                             \
351
213k
        }                                                                      \
352
1.35M
        case WT_DATA:                                                          \
353
1.35M
        {                                                                      \
354
1.35M
            unsigned int nDataLength;                                          \
355
1.35M
            READ_SIZE(pabyData, pabyDataLimit, nDataLength);                   \
356
1.34M
            pabyData += nDataLength;                                           \
357
1.34M
            break;                                                             \
358
1.35M
        }                                                                      \
359
1.35M
        case WT_32BIT:                                                         \
360
1.04M
        {                                                                      \
361
1.04M
            if (CHECK_OOB && pabyDataLimit - pabyData < 4)                     \
362
1.04M
                THROW_GPB_EXCEPTION;                                           \
363
1.04M
            pabyData += 4;                                                     \
364
1.04M
            break;                                                             \
365
1.04M
        }                                                                      \
366
1.04M
        default:                                                               \
367
45.0k
            THROW_GPB_EXCEPTION;                                               \
368
14.4M
    }
369
370
inline int SkipUnknownField(int nKey, const GByte *pabyData,
371
                            const GByte *pabyDataLimit, int verbose)
372
14.4M
{
373
14.4M
    const GByte *pabyDataBefore = pabyData;
374
14.4M
    try
375
14.4M
    {
376
14.4M
        SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
377
14.3M
        return static_cast<int>(pabyData - pabyDataBefore);
378
14.4M
    }
379
14.4M
    catch (const GPBException &e)
380
14.4M
    {
381
66.0k
        if (verbose)
382
17
        {
383
17
            CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
384
17
        }
385
66.0k
        return -1;
386
66.0k
    }
387
14.4M
}
388
389
#define SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, verbose)                   \
390
14.4M
    {                                                                          \
391
14.4M
        int _nOffset =                                                         \
392
14.4M
            SkipUnknownField(nKey, pabyData, pabyDataLimit, verbose);          \
393
14.4M
        if (_nOffset < 0)                                                      \
394
14.4M
            THROW_GPB_EXCEPTION;                                               \
395
14.4M
        pabyData += _nOffset;                                                  \
396
14.3M
    }
397
398
/************************************************************************/
399
/*                           GetVarUIntSize()                           */
400
/************************************************************************/
401
402
inline int GetVarUIntSize(GUIntBig nVal)
403
0
{
404
0
    int nBytes = 1;
405
0
    while (nVal > 127)
406
0
    {
407
0
        nBytes++;
408
0
        nVal >>= 7;
409
0
    }
410
0
    return nBytes;
411
0
}
412
413
/************************************************************************/
414
/*                             EncodeSInt()                             */
415
/************************************************************************/
416
417
inline GUIntBig EncodeSInt(GIntBig nVal)
418
0
{
419
0
    if (nVal < 0)
420
0
        return (static_cast<GUIntBig>(-(nVal + 1)) << 1) | 1;
421
0
    else
422
0
        return static_cast<GUIntBig>(nVal) << 1;
423
0
}
424
425
inline GUInt32 EncodeSInt(GInt32 nVal)
426
0
{
427
0
    if (nVal < 0)
428
0
        return (static_cast<GUInt32>(-(nVal + 1)) << 1) | 1;
429
0
    else
430
0
        return static_cast<GUInt32>(nVal) << 1;
431
0
}
432
433
/************************************************************************/
434
/*                           GetVarIntSize()                            */
435
/************************************************************************/
436
437
inline int GetVarIntSize(GIntBig nVal)
438
0
{
439
0
    return GetVarUIntSize(static_cast<GUIntBig>(nVal));
440
0
}
441
442
/************************************************************************/
443
/*                           GetVarSIntSize()                           */
444
/************************************************************************/
445
446
inline int GetVarSIntSize(GIntBig nVal)
447
0
{
448
0
    return GetVarUIntSize(EncodeSInt(nVal));
449
0
}
450
451
/************************************************************************/
452
/*                            WriteVarUInt()                            */
453
/************************************************************************/
454
455
inline void WriteVarUInt(GByte **ppabyData, GUIntBig nVal)
456
0
{
457
0
    GByte *pabyData = *ppabyData;
458
0
    while (nVal > 127)
459
0
    {
460
0
        *pabyData = static_cast<GByte>((nVal & 0x7f) | 0x80);
461
0
        pabyData++;
462
0
        nVal >>= 7;
463
0
    }
464
0
    *pabyData = static_cast<GByte>(nVal);
465
0
    pabyData++;
466
0
    *ppabyData = pabyData;
467
0
}
468
469
/************************************************************************/
470
/*                       WriteVarUIntSingleByte()                       */
471
/************************************************************************/
472
473
inline void WriteVarUIntSingleByte(GByte **ppabyData, GUIntBig nVal)
474
0
{
475
0
    GByte *pabyData = *ppabyData;
476
0
    CPLAssert(nVal < 128);
477
0
    *pabyData = static_cast<GByte>(nVal);
478
0
    pabyData++;
479
0
    *ppabyData = pabyData;
480
0
}
481
482
/************************************************************************/
483
/*                            WriteVarInt()                             */
484
/************************************************************************/
485
486
inline void WriteVarInt(GByte **ppabyData, GIntBig nVal)
487
0
{
488
0
    WriteVarUInt(ppabyData, static_cast<GUIntBig>(nVal));
489
0
}
490
491
/************************************************************************/
492
/*                            WriteVarSInt()                            */
493
/************************************************************************/
494
495
inline void WriteVarSInt(GByte **ppabyData, GIntBig nVal)
496
0
{
497
0
    WriteVarUInt(ppabyData, EncodeSInt(nVal));
498
0
}
499
500
/************************************************************************/
501
/*                            WriteFloat32()                            */
502
/************************************************************************/
503
504
inline void WriteFloat32(GByte **ppabyData, float fVal)
505
0
{
506
0
    CPL_LSBPTR32(&fVal);
507
0
    memcpy(*ppabyData, &fVal, sizeof(float));
508
0
    *ppabyData += sizeof(float);
509
0
}
510
511
/************************************************************************/
512
/*                            WriteFloat64()                            */
513
/************************************************************************/
514
515
inline void WriteFloat64(GByte **ppabyData, double dfVal)
516
0
{
517
0
    CPL_LSBPTR64(&dfVal);
518
0
    memcpy(*ppabyData, &dfVal, sizeof(double));
519
0
    *ppabyData += sizeof(double);
520
0
}
521
522
/************************************************************************/
523
/*                            GetTextSize()                             */
524
/************************************************************************/
525
526
inline int GetTextSize(const char *pszText)
527
0
{
528
0
    size_t nTextSize = strlen(pszText);
529
0
    return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
530
0
}
531
532
inline int GetTextSize(const std::string &osText)
533
0
{
534
0
    size_t nTextSize = osText.size();
535
0
    return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
536
0
}
537
538
/************************************************************************/
539
/*                             WriteText()                              */
540
/************************************************************************/
541
542
inline void WriteText(GByte **ppabyData, const char *pszText)
543
0
{
544
0
    size_t nTextSize = strlen(pszText);
545
0
    WriteVarUInt(ppabyData, nTextSize);
546
0
    memcpy(*ppabyData, pszText, nTextSize);
547
0
    *ppabyData += nTextSize;
548
0
}
549
550
inline void WriteText(GByte **ppabyData, const std::string &osText)
551
0
{
552
0
    size_t nTextSize = osText.size();
553
0
    WriteVarUInt(ppabyData, nTextSize);
554
0
    memcpy(*ppabyData, osText.c_str(), nTextSize);
555
0
    *ppabyData += nTextSize;
556
0
}
557
558
#endif /* GPB_H_INCLUDED */