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