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 : 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 372597 : inline int ReadVarUInt32(const GByte **ppabyData)
75 : {
76 372597 : unsigned int nVal = 0;
77 372597 : int nShift = 0;
78 372597 : const GByte *pabyData = *ppabyData;
79 :
80 : while (true)
81 : {
82 382287 : int nByte = *pabyData;
83 382287 : if (!(nByte & 0x80))
84 : {
85 372597 : *ppabyData = pabyData + 1;
86 372597 : return nVal | (static_cast<unsigned>(nByte) << nShift);
87 : }
88 9690 : nVal |= (nByte & 0x7f) << nShift;
89 9690 : pabyData++;
90 9690 : nShift += 7;
91 9690 : 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 9690 : }
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 883392 : inline GUIntBig ReadVarUInt64(const GByte **ppabyData)
125 : {
126 883392 : GUIntBig nVal = 0;
127 883392 : int nShift = 0;
128 883392 : const GByte *pabyData = *ppabyData;
129 :
130 : while (true)
131 : {
132 938902 : int nByte = *pabyData;
133 938902 : if (!(nByte & 0x80))
134 : {
135 883270 : *ppabyData = pabyData + 1;
136 883270 : return nVal | (static_cast<GUIntBig>(nByte) << nShift);
137 : }
138 55632 : nVal |= (static_cast<GUIntBig>(nByte & 0x7f)) << nShift;
139 55632 : pabyData++;
140 55632 : nShift += 7;
141 55632 : if (nShift == 63)
142 : {
143 122 : nByte = *pabyData;
144 122 : if (!(nByte & 0x80))
145 : {
146 117 : *ppabyData = pabyData + 1;
147 117 : return nVal | ((static_cast<GUIntBig>(nByte) & 1) << nShift);
148 : }
149 5 : *ppabyData = pabyData;
150 5 : return nVal;
151 : }
152 55510 : }
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 3042 : inline GIntBig ReadVarInt64(const GByte **ppabyData)
175 : {
176 3042 : 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 28526 : inline GIntBig DecodeSInt(GUIntBig nVal)
191 : {
192 28526 : return ((nVal & 1) == 0) ? static_cast<GIntBig>(nVal >> 1)
193 28526 : : -static_cast<GIntBig>(nVal >> 1) - 1;
194 : }
195 :
196 712141 : inline GInt32 DecodeSInt(GUInt32 nVal)
197 : {
198 712141 : return ((nVal & 1) == 0) ? static_cast<GInt32>(nVal >> 1)
199 712141 : : -static_cast<GInt32>(nVal >> 1) - 1;
200 : }
201 :
202 : /************************************************************************/
203 : /* ReadVarSInt64() */
204 : /************************************************************************/
205 :
206 28526 : inline GIntBig ReadVarSInt64(const GByte **ppabyPtr)
207 : {
208 28526 : 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 132533 : 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 132533 : GIntBig nVal = static_cast<GIntBig>(ReadVarUInt64(ppabyData));
232 132533 : 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 623 : inline float ReadFloat32(const GByte **ppabyData, const GByte *pabyDataLimit)
254 : {
255 623 : if (*ppabyData + sizeof(float) > pabyDataLimit)
256 0 : THROW_GPB_EXCEPTION;
257 : float fValue;
258 623 : memcpy(&fValue, *ppabyData, sizeof(float));
259 623 : CPL_LSBPTR32(&fValue);
260 623 : *ppabyData += sizeof(float);
261 623 : return fValue;
262 : }
263 :
264 : /************************************************************************/
265 : /* ReadFloat64() */
266 : /************************************************************************/
267 :
268 1519 : inline double ReadFloat64(const GByte **ppabyData, const GByte *pabyDataLimit)
269 : {
270 1519 : if (*ppabyData + sizeof(double) > pabyDataLimit)
271 0 : THROW_GPB_EXCEPTION;
272 : double dfValue;
273 1519 : memcpy(&dfValue, *ppabyData, sizeof(double));
274 1519 : CPL_LSBPTR64(&dfValue);
275 1519 : *ppabyData += sizeof(double);
276 1519 : return dfValue;
277 : }
278 :
279 : /************************************************************************/
280 : /* SkipVarInt() */
281 : /************************************************************************/
282 :
283 24240 : inline void SkipVarInt(const GByte **ppabyData)
284 : {
285 24240 : const GByte *pabyData = *ppabyData;
286 : while (true)
287 : {
288 27755 : int nByte = *pabyData;
289 27755 : if (!(nByte & 0x80))
290 : {
291 24240 : *ppabyData = pabyData + 1;
292 24240 : return;
293 : }
294 3515 : pabyData++;
295 3515 : }
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 76091 : inline int SkipUnknownField(int nKey, const GByte *pabyData,
371 : const GByte *pabyDataLimit, int verbose)
372 : {
373 76091 : const GByte *pabyDataBefore = pabyData;
374 : try
375 : {
376 76091 : SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
377 76091 : 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 114302 : inline int GetVarUIntSize(GUIntBig nVal)
403 : {
404 114302 : int nBytes = 1;
405 125514 : while (nVal > 127)
406 : {
407 11212 : nBytes++;
408 11212 : nVal >>= 7;
409 : }
410 114302 : return nBytes;
411 : }
412 :
413 : /************************************************************************/
414 : /* EncodeSInt() */
415 : /************************************************************************/
416 :
417 130 : inline GUIntBig EncodeSInt(GIntBig nVal)
418 : {
419 130 : if (nVal < 0)
420 123 : return (static_cast<GUIntBig>(-(nVal + 1)) << 1) | 1;
421 : else
422 7 : return static_cast<GUIntBig>(nVal) << 1;
423 : }
424 :
425 6208 : inline GUInt32 EncodeSInt(GInt32 nVal)
426 : {
427 6208 : if (nVal < 0)
428 732 : return (static_cast<GUInt32>(-(nVal + 1)) << 1) | 1;
429 : else
430 5476 : 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 95 : inline int GetVarSIntSize(GIntBig nVal)
447 : {
448 95 : return GetVarUIntSize(EncodeSInt(nVal));
449 : }
450 :
451 : /************************************************************************/
452 : /* WriteVarUInt() */
453 : /************************************************************************/
454 :
455 70565 : inline void WriteVarUInt(GByte **ppabyData, GUIntBig nVal)
456 : {
457 70565 : GByte *pabyData = *ppabyData;
458 77145 : while (nVal > 127)
459 : {
460 6580 : *pabyData = static_cast<GByte>((nVal & 0x7f) | 0x80);
461 6580 : pabyData++;
462 6580 : nVal >>= 7;
463 : }
464 70565 : *pabyData = static_cast<GByte>(nVal);
465 70565 : pabyData++;
466 70565 : *ppabyData = pabyData;
467 70565 : }
468 :
469 : /************************************************************************/
470 : /* WriteVarUIntSingleByte() */
471 : /************************************************************************/
472 :
473 47874 : inline void WriteVarUIntSingleByte(GByte **ppabyData, GUIntBig nVal)
474 : {
475 47874 : GByte *pabyData = *ppabyData;
476 47874 : CPLAssert(nVal < 128);
477 47874 : *pabyData = static_cast<GByte>(nVal);
478 47874 : pabyData++;
479 47874 : *ppabyData = pabyData;
480 47874 : }
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 35 : inline void WriteVarSInt(GByte **ppabyData, GIntBig nVal)
496 : {
497 35 : WriteVarUInt(ppabyData, EncodeSInt(nVal));
498 33 : }
499 :
500 : /************************************************************************/
501 : /* WriteFloat32() */
502 : /************************************************************************/
503 :
504 50 : inline void WriteFloat32(GByte **ppabyData, float fVal)
505 : {
506 50 : CPL_LSBPTR32(&fVal);
507 50 : memcpy(*ppabyData, &fVal, sizeof(float));
508 50 : *ppabyData += sizeof(float);
509 50 : }
510 :
511 : /************************************************************************/
512 : /* WriteFloat64() */
513 : /************************************************************************/
514 :
515 1577 : inline void WriteFloat64(GByte **ppabyData, double dfVal)
516 : {
517 1577 : CPL_LSBPTR64(&dfVal);
518 1578 : memcpy(*ppabyData, &dfVal, sizeof(double));
519 1578 : *ppabyData += sizeof(double);
520 1578 : }
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 10964 : inline int GetTextSize(const std::string &osText)
533 : {
534 10964 : size_t nTextSize = osText.size();
535 10961 : 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 10954 : inline void WriteText(GByte **ppabyData, const std::string &osText)
551 : {
552 10954 : size_t nTextSize = osText.size();
553 10953 : WriteVarUInt(ppabyData, nTextSize);
554 10953 : memcpy(*ppabyData, osText.c_str(), nTextSize);
555 10955 : *ppabyData += nTextSize;
556 10955 : }
557 :
558 : #endif /* GPB_H_INCLUDED */
|