Line data Source code
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 : #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 6 : explicit GPBException(int nLine)
38 6 : : m_osMessage(CPLSPrintf("Parsing error occurred at line %d", nLine))
39 : {
40 6 : }
41 :
42 2 : const char *what() const noexcept override
43 : {
44 2 : return m_osMessage.c_str();
45 : }
46 : };
47 :
48 : #if defined(__clang__)
49 : #pragma clang diagnostic pop
50 : #endif
51 :
52 : #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 : #define MAKE_KEY(nFieldNumber, nWireType) ((nFieldNumber << 3) | nWireType)
67 : #define GET_WIRETYPE(nKey) (nKey & 0x7)
68 : #define GET_FIELDNUMBER(nKey) (nKey >> 3)
69 :
70 : /************************************************************************/
71 : /* ReadVarUInt32() */
72 : /************************************************************************/
73 :
74 384839 : inline int ReadVarUInt32(const GByte **ppabyData)
75 : {
76 384839 : unsigned int nVal = 0;
77 384839 : int nShift = 0;
78 384839 : const GByte *pabyData = *ppabyData;
79 :
80 : while (true)
81 : {
82 394792 : int nByte = *pabyData;
83 394792 : if (!(nByte & 0x80))
84 : {
85 384839 : *ppabyData = pabyData + 1;
86 384839 : return nVal | (static_cast<unsigned>(nByte) << nShift);
87 : }
88 9953 : nVal |= (nByte & 0x7f) << nShift;
89 9953 : pabyData++;
90 9953 : nShift += 7;
91 9953 : if (nShift == 28)
92 : {
93 0 : nByte = *pabyData;
94 0 : if (!(nByte & 0x80))
95 : {
96 0 : *ppabyData = pabyData + 1;
97 0 : return nVal | ((static_cast<unsigned>(nByte) & 0xf) << nShift);
98 : }
99 0 : *ppabyData = pabyData;
100 0 : return nVal;
101 : }
102 9953 : }
103 : }
104 :
105 : #define READ_VARUINT32(pabyData, pabyDataLimit, nVal) \
106 : { \
107 : nVal = ReadVarUInt32(&pabyData); \
108 : if (CHECK_OOB && pabyData > pabyDataLimit) \
109 : THROW_GPB_EXCEPTION; \
110 : }
111 :
112 : #define READ_SIZE(pabyData, pabyDataLimit, nSize) \
113 : { \
114 : READ_VARUINT32(pabyData, pabyDataLimit, nSize); \
115 : if (CHECK_OOB && \
116 : nSize > static_cast<unsigned int>(pabyDataLimit - pabyData)) \
117 : THROW_GPB_EXCEPTION; \
118 : }
119 :
120 : /************************************************************************/
121 : /* ReadVarUInt64() */
122 : /************************************************************************/
123 :
124 915782 : inline GUIntBig ReadVarUInt64(const GByte **ppabyData)
125 : {
126 915782 : GUIntBig nVal = 0;
127 915782 : int nShift = 0;
128 915782 : const GByte *pabyData = *ppabyData;
129 :
130 : while (true)
131 : {
132 971977 : int nByte = *pabyData;
133 971977 : if (!(nByte & 0x80))
134 : {
135 915656 : *ppabyData = pabyData + 1;
136 915656 : return nVal | (static_cast<GUIntBig>(nByte) << nShift);
137 : }
138 56321 : nVal |= (static_cast<GUIntBig>(nByte & 0x7f)) << nShift;
139 56321 : pabyData++;
140 56321 : nShift += 7;
141 56321 : if (nShift == 63)
142 : {
143 126 : nByte = *pabyData;
144 126 : if (!(nByte & 0x80))
145 : {
146 121 : *ppabyData = pabyData + 1;
147 121 : return nVal | ((static_cast<GUIntBig>(nByte) & 1) << nShift);
148 : }
149 5 : *ppabyData = pabyData;
150 5 : return nVal;
151 : }
152 56195 : }
153 : }
154 :
155 : #define READ_VARUINT64(pabyData, pabyDataLimit, nVal) \
156 : { \
157 : nVal = ReadVarUInt64(&pabyData); \
158 : if (CHECK_OOB && pabyData > pabyDataLimit) \
159 : THROW_GPB_EXCEPTION; \
160 : }
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 3050 : inline GIntBig ReadVarInt64(const GByte **ppabyData)
175 : {
176 3050 : return static_cast<GIntBig>(ReadVarUInt64(ppabyData));
177 : }
178 :
179 : #define READ_VARINT64(pabyData, pabyDataLimit, nVal) \
180 : { \
181 : nVal = ReadVarInt64(&pabyData); \
182 : if (CHECK_OOB && pabyData > pabyDataLimit) \
183 : THROW_GPB_EXCEPTION; \
184 : }
185 :
186 : /************************************************************************/
187 : /* DecodeSInt() */
188 : /************************************************************************/
189 :
190 28544 : inline GIntBig DecodeSInt(GUIntBig nVal)
191 : {
192 28544 : return ((nVal & 1) == 0) ? static_cast<GIntBig>(nVal >> 1)
193 28544 : : -static_cast<GIntBig>(nVal >> 1) - 1;
194 : }
195 :
196 740949 : inline GInt32 DecodeSInt(GUInt32 nVal)
197 : {
198 740949 : return ((nVal & 1) == 0) ? static_cast<GInt32>(nVal >> 1)
199 740949 : : -static_cast<GInt32>(nVal >> 1) - 1;
200 : }
201 :
202 : /************************************************************************/
203 : /* ReadVarSInt64() */
204 : /************************************************************************/
205 :
206 28544 : inline GIntBig ReadVarSInt64(const GByte **ppabyPtr)
207 : {
208 28544 : return DecodeSInt(ReadVarUInt64(ppabyPtr));
209 : }
210 :
211 : #define READ_VARSINT64(pabyData, pabyDataLimit, nVal) \
212 : { \
213 : nVal = ReadVarSInt64(&pabyData); \
214 : if (CHECK_OOB && pabyData > pabyDataLimit) \
215 : THROW_GPB_EXCEPTION; \
216 : }
217 :
218 : #define READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nVal) \
219 : { \
220 : nVal = ReadVarSInt64(&pabyData); \
221 : }
222 :
223 : /************************************************************************/
224 : /* ReadVarInt32() */
225 : /************************************************************************/
226 :
227 135815 : inline int ReadVarInt32(const GByte **ppabyData)
228 : {
229 : /* If you use int32 or int64 as the type for a negative number, */
230 : /* the resulting varint is always ten bytes long */
231 135815 : GIntBig nVal = static_cast<GIntBig>(ReadVarUInt64(ppabyData));
232 135815 : return static_cast<int>(nVal);
233 : }
234 :
235 : #define READ_VARINT32(pabyData, pabyDataLimit, nVal) \
236 : { \
237 : nVal = ReadVarInt32(&pabyData); \
238 : if (CHECK_OOB && pabyData > pabyDataLimit) \
239 : THROW_GPB_EXCEPTION; \
240 : }
241 :
242 : #define READ_VARSINT32(pabyData, pabyDataLimit, nVal) \
243 : { \
244 : nVal = DecodeSInt(static_cast<GUInt32>(ReadVarUInt64(&pabyData))); \
245 : if (CHECK_OOB && pabyData > pabyDataLimit) \
246 : THROW_GPB_EXCEPTION; \
247 : }
248 :
249 : /************************************************************************/
250 : /* ReadFloat32() */
251 : /************************************************************************/
252 :
253 633 : inline float ReadFloat32(const GByte **ppabyData, const GByte *pabyDataLimit)
254 : {
255 633 : if (*ppabyData + sizeof(float) > pabyDataLimit)
256 0 : THROW_GPB_EXCEPTION;
257 : float fValue;
258 633 : memcpy(&fValue, *ppabyData, sizeof(float));
259 633 : CPL_LSBPTR32(&fValue);
260 633 : *ppabyData += sizeof(float);
261 633 : return fValue;
262 : }
263 :
264 : /************************************************************************/
265 : /* ReadFloat64() */
266 : /************************************************************************/
267 :
268 1547 : inline double ReadFloat64(const GByte **ppabyData, const GByte *pabyDataLimit)
269 : {
270 1547 : if (*ppabyData + sizeof(double) > pabyDataLimit)
271 0 : THROW_GPB_EXCEPTION;
272 : double dfValue;
273 1547 : memcpy(&dfValue, *ppabyData, sizeof(double));
274 1547 : CPL_LSBPTR64(&dfValue);
275 1547 : *ppabyData += sizeof(double);
276 1547 : return dfValue;
277 : }
278 :
279 : /************************************************************************/
280 : /* SkipVarInt() */
281 : /************************************************************************/
282 :
283 24582 : inline void SkipVarInt(const GByte **ppabyData)
284 : {
285 24582 : const GByte *pabyData = *ppabyData;
286 : while (true)
287 : {
288 28132 : int nByte = *pabyData;
289 28132 : if (!(nByte & 0x80))
290 : {
291 24582 : *ppabyData = pabyData + 1;
292 24582 : return;
293 : }
294 3550 : pabyData++;
295 3550 : }
296 : }
297 :
298 : #define SKIP_VARINT(pabyData, pabyDataLimit) \
299 : { \
300 : SkipVarInt(&pabyData); \
301 : if (CHECK_OOB && pabyData > pabyDataLimit) \
302 : THROW_GPB_EXCEPTION; \
303 : }
304 :
305 : #define READ_FIELD_KEY(nKey) READ_VARINT32(pabyData, pabyDataLimit, nKey)
306 :
307 : #define READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength) \
308 : do \
309 : { \
310 : READ_SIZE(pabyData, pabyDataLimit, l_nDataLength); \
311 : pszTxt = static_cast<char *>(VSI_MALLOC_VERBOSE(l_nDataLength + 1)); \
312 : if (pszTxt == nullptr) \
313 : THROW_GPB_EXCEPTION; \
314 : memcpy(pszTxt, pabyData, l_nDataLength); \
315 : pszTxt[l_nDataLength] = 0; \
316 : pabyData += l_nDataLength; \
317 : } while (0)
318 :
319 : #define READ_TEXT(pabyData, pabyDataLimit, pszTxt) \
320 : do \
321 : { \
322 : unsigned int l_nDataLength; \
323 : READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength); \
324 : } while (0)
325 :
326 : /************************************************************************/
327 : /* SkipUnknownField() */
328 : /************************************************************************/
329 :
330 : #define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose) \
331 : int nWireType = GET_WIRETYPE(nKey); \
332 : if (verbose) \
333 : { \
334 : int nFieldNumber = GET_FIELDNUMBER(nKey); \
335 : CPLDebug("PBF", "Unhandled case: nFieldNumber = %d, nWireType = %d", \
336 : nFieldNumber, nWireType); \
337 : } \
338 : switch (nWireType) \
339 : { \
340 : case WT_VARINT: \
341 : { \
342 : SKIP_VARINT(pabyData, pabyDataLimit); \
343 : break; \
344 : } \
345 : case WT_64BIT: \
346 : { \
347 : if (CHECK_OOB && pabyDataLimit - pabyData < 8) \
348 : THROW_GPB_EXCEPTION; \
349 : pabyData += 8; \
350 : break; \
351 : } \
352 : case WT_DATA: \
353 : { \
354 : unsigned int nDataLength; \
355 : READ_SIZE(pabyData, pabyDataLimit, nDataLength); \
356 : pabyData += nDataLength; \
357 : break; \
358 : } \
359 : case WT_32BIT: \
360 : { \
361 : if (CHECK_OOB && pabyDataLimit - pabyData < 4) \
362 : THROW_GPB_EXCEPTION; \
363 : pabyData += 4; \
364 : break; \
365 : } \
366 : default: \
367 : THROW_GPB_EXCEPTION; \
368 : }
369 :
370 78898 : inline int SkipUnknownField(int nKey, const GByte *pabyData,
371 : const GByte *pabyDataLimit, int verbose)
372 : {
373 78898 : const GByte *pabyDataBefore = pabyData;
374 : try
375 : {
376 78898 : SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
377 78898 : return static_cast<int>(pabyData - pabyDataBefore);
378 : }
379 0 : catch (const GPBException &e)
380 : {
381 0 : if (verbose)
382 : {
383 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
384 : }
385 0 : return -1;
386 : }
387 : }
388 :
389 : #define SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, verbose) \
390 : { \
391 : int _nOffset = \
392 : SkipUnknownField(nKey, pabyData, pabyDataLimit, verbose); \
393 : if (_nOffset < 0) \
394 : THROW_GPB_EXCEPTION; \
395 : pabyData += _nOffset; \
396 : }
397 :
398 : /************************************************************************/
399 : /* GetVarUIntSize() */
400 : /************************************************************************/
401 :
402 113833 : inline int GetVarUIntSize(GUIntBig nVal)
403 : {
404 113833 : int nBytes = 1;
405 125023 : while (nVal > 127)
406 : {
407 11190 : nBytes++;
408 11190 : nVal >>= 7;
409 : }
410 113833 : return nBytes;
411 : }
412 :
413 : /************************************************************************/
414 : /* EncodeSInt() */
415 : /************************************************************************/
416 :
417 127 : inline GUIntBig EncodeSInt(GIntBig nVal)
418 : {
419 127 : if (nVal < 0)
420 120 : return (static_cast<GUIntBig>(-(nVal + 1)) << 1) | 1;
421 : else
422 7 : return static_cast<GUIntBig>(nVal) << 1;
423 : }
424 :
425 6178 : inline GUInt32 EncodeSInt(GInt32 nVal)
426 : {
427 6178 : if (nVal < 0)
428 733 : return (static_cast<GUInt32>(-(nVal + 1)) << 1) | 1;
429 : else
430 5445 : return static_cast<GUInt32>(nVal) << 1;
431 : }
432 :
433 : /************************************************************************/
434 : /* GetVarIntSize() */
435 : /************************************************************************/
436 :
437 8 : inline int GetVarIntSize(GIntBig nVal)
438 : {
439 8 : return GetVarUIntSize(static_cast<GUIntBig>(nVal));
440 : }
441 :
442 : /************************************************************************/
443 : /* GetVarSIntSize() */
444 : /************************************************************************/
445 :
446 93 : inline int GetVarSIntSize(GIntBig nVal)
447 : {
448 93 : return GetVarUIntSize(EncodeSInt(nVal));
449 : }
450 :
451 : /************************************************************************/
452 : /* WriteVarUInt() */
453 : /************************************************************************/
454 :
455 70271 : inline void WriteVarUInt(GByte **ppabyData, GUIntBig nVal)
456 : {
457 70271 : GByte *pabyData = *ppabyData;
458 76834 : while (nVal > 127)
459 : {
460 6563 : *pabyData = static_cast<GByte>((nVal & 0x7f) | 0x80);
461 6563 : pabyData++;
462 6563 : nVal >>= 7;
463 : }
464 70271 : *pabyData = static_cast<GByte>(nVal);
465 70271 : pabyData++;
466 70271 : *ppabyData = pabyData;
467 70271 : }
468 :
469 : /************************************************************************/
470 : /* WriteVarUIntSingleByte() */
471 : /************************************************************************/
472 :
473 47694 : inline void WriteVarUIntSingleByte(GByte **ppabyData, GUIntBig nVal)
474 : {
475 47694 : GByte *pabyData = *ppabyData;
476 47694 : CPLAssert(nVal < 128);
477 47694 : *pabyData = static_cast<GByte>(nVal);
478 47694 : pabyData++;
479 47694 : *ppabyData = pabyData;
480 47694 : }
481 :
482 : /************************************************************************/
483 : /* WriteVarInt() */
484 : /************************************************************************/
485 :
486 3 : inline void WriteVarInt(GByte **ppabyData, GIntBig nVal)
487 : {
488 3 : WriteVarUInt(ppabyData, static_cast<GUIntBig>(nVal));
489 3 : }
490 :
491 : /************************************************************************/
492 : /* WriteVarSInt() */
493 : /************************************************************************/
494 :
495 33 : inline void WriteVarSInt(GByte **ppabyData, GIntBig nVal)
496 : {
497 33 : WriteVarUInt(ppabyData, EncodeSInt(nVal));
498 33 : }
499 :
500 : /************************************************************************/
501 : /* WriteFloat32() */
502 : /************************************************************************/
503 :
504 49 : inline void WriteFloat32(GByte **ppabyData, float fVal)
505 : {
506 49 : CPL_LSBPTR32(&fVal);
507 49 : memcpy(*ppabyData, &fVal, sizeof(float));
508 49 : *ppabyData += sizeof(float);
509 49 : }
510 :
511 : /************************************************************************/
512 : /* WriteFloat64() */
513 : /************************************************************************/
514 :
515 1572 : inline void WriteFloat64(GByte **ppabyData, double dfVal)
516 : {
517 1572 : CPL_LSBPTR64(&dfVal);
518 1565 : memcpy(*ppabyData, &dfVal, sizeof(double));
519 1565 : *ppabyData += sizeof(double);
520 1565 : }
521 :
522 : /************************************************************************/
523 : /* GetTextSize() */
524 : /************************************************************************/
525 :
526 2 : inline int GetTextSize(const char *pszText)
527 : {
528 2 : size_t nTextSize = strlen(pszText);
529 2 : return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
530 : }
531 :
532 10903 : inline int GetTextSize(const std::string &osText)
533 : {
534 10903 : size_t nTextSize = osText.size();
535 10893 : return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
536 : }
537 :
538 : /************************************************************************/
539 : /* WriteText() */
540 : /************************************************************************/
541 :
542 1 : inline void WriteText(GByte **ppabyData, const char *pszText)
543 : {
544 1 : size_t nTextSize = strlen(pszText);
545 1 : WriteVarUInt(ppabyData, nTextSize);
546 1 : memcpy(*ppabyData, pszText, nTextSize);
547 1 : *ppabyData += nTextSize;
548 1 : }
549 :
550 10880 : inline void WriteText(GByte **ppabyData, const std::string &osText)
551 : {
552 10880 : size_t nTextSize = osText.size();
553 10883 : WriteVarUInt(ppabyData, nTextSize);
554 10887 : memcpy(*ppabyData, osText.c_str(), nTextSize);
555 10896 : *ppabyData += nTextSize;
556 10896 : }
557 :
558 : #endif /* GPB_H_INCLUDED */
|