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