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 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #ifndef GPB_H_INCLUDED
31 : #define GPB_H_INCLUDED
32 :
33 : #include "cpl_port.h"
34 : #include "cpl_error.h"
35 : #include "cpl_string.h"
36 :
37 : #include <string>
38 : #include <exception>
39 :
40 : #ifndef CHECK_OOB
41 : #define CHECK_OOB 1
42 : #endif
43 :
44 : class GPBException : public std::exception
45 : {
46 : std::string m_osMessage;
47 :
48 : public:
49 6 : explicit GPBException(int nLine)
50 6 : : m_osMessage(CPLSPrintf("Parsing error occurred at line %d", nLine))
51 : {
52 6 : }
53 :
54 2 : const char *what() const noexcept override
55 : {
56 2 : return m_osMessage.c_str();
57 : }
58 : };
59 :
60 : #define THROW_GPB_EXCEPTION throw GPBException(__LINE__)
61 :
62 : /************************************************************************/
63 : /* Google Protocol Buffer definitions */
64 : /************************************************************************/
65 :
66 : // TODO(schwehr): This should be an enum.
67 : constexpr int WT_VARINT = 0;
68 : constexpr int WT_64BIT = 1;
69 : constexpr int WT_DATA = 2;
70 : // constexpr WT_STARTGROUP = 3; // unused
71 : // constexpr WT_ENDGROUP = 4; // unused
72 : constexpr int WT_32BIT = 5;
73 :
74 : #define MAKE_KEY(nFieldNumber, nWireType) ((nFieldNumber << 3) | nWireType)
75 : #define GET_WIRETYPE(nKey) (nKey & 0x7)
76 : #define GET_FIELDNUMBER(nKey) (nKey >> 3)
77 :
78 : /************************************************************************/
79 : /* ReadVarUInt32() */
80 : /************************************************************************/
81 :
82 369759 : inline int ReadVarUInt32(const GByte **ppabyData)
83 : {
84 369759 : unsigned int nVal = 0;
85 369759 : int nShift = 0;
86 369759 : const GByte *pabyData = *ppabyData;
87 :
88 : while (true)
89 : {
90 379124 : int nByte = *pabyData;
91 379124 : if (!(nByte & 0x80))
92 : {
93 369759 : *ppabyData = pabyData + 1;
94 369759 : return nVal | ((unsigned)nByte << nShift);
95 : }
96 9365 : nVal |= (nByte & 0x7f) << nShift;
97 9365 : pabyData++;
98 9365 : nShift += 7;
99 9365 : if (nShift == 28)
100 : {
101 0 : nByte = *pabyData;
102 0 : if (!(nByte & 0x80))
103 : {
104 0 : *ppabyData = pabyData + 1;
105 0 : return nVal | (((unsigned)nByte & 0xf) << nShift);
106 : }
107 0 : *ppabyData = pabyData;
108 0 : return nVal;
109 : }
110 9365 : }
111 : }
112 :
113 : #define READ_VARUINT32(pabyData, pabyDataLimit, nVal) \
114 : { \
115 : nVal = ReadVarUInt32(&pabyData); \
116 : if (CHECK_OOB && pabyData > pabyDataLimit) \
117 : THROW_GPB_EXCEPTION; \
118 : }
119 :
120 : #define READ_SIZE(pabyData, pabyDataLimit, nSize) \
121 : { \
122 : READ_VARUINT32(pabyData, pabyDataLimit, nSize); \
123 : if (CHECK_OOB && nSize > (unsigned int)(pabyDataLimit - pabyData)) \
124 : THROW_GPB_EXCEPTION; \
125 : }
126 :
127 : /************************************************************************/
128 : /* ReadVarUInt64() */
129 : /************************************************************************/
130 :
131 878385 : inline GUIntBig ReadVarUInt64(const GByte **ppabyData)
132 : {
133 878385 : GUIntBig nVal = 0;
134 878385 : int nShift = 0;
135 878385 : const GByte *pabyData = *ppabyData;
136 :
137 : while (true)
138 : {
139 932470 : int nByte = *pabyData;
140 932470 : if (!(nByte & 0x80))
141 : {
142 878263 : *ppabyData = pabyData + 1;
143 878263 : return nVal | ((GUIntBig)nByte << nShift);
144 : }
145 54207 : nVal |= ((GUIntBig)(nByte & 0x7f)) << nShift;
146 54207 : pabyData++;
147 54207 : nShift += 7;
148 54207 : if (nShift == 63)
149 : {
150 122 : nByte = *pabyData;
151 122 : if (!(nByte & 0x80))
152 : {
153 117 : *ppabyData = pabyData + 1;
154 117 : return nVal | (((GUIntBig)nByte & 1) << nShift);
155 : }
156 5 : *ppabyData = pabyData;
157 5 : return nVal;
158 : }
159 54085 : }
160 : }
161 :
162 : #define READ_VARUINT64(pabyData, pabyDataLimit, nVal) \
163 : { \
164 : nVal = ReadVarUInt64(&pabyData); \
165 : if (CHECK_OOB && pabyData > pabyDataLimit) \
166 : THROW_GPB_EXCEPTION; \
167 : }
168 :
169 : #define READ_SIZE64(pabyData, pabyDataLimit, nSize) \
170 : { \
171 : READ_VARUINT64(pabyData, pabyDataLimit, nSize); \
172 : if (CHECK_OOB && nSize > (unsigned int)(pabyDataLimit - pabyData)) \
173 : THROW_GPB_EXCEPTION; \
174 : }
175 :
176 : /************************************************************************/
177 : /* ReadVarInt64() */
178 : /************************************************************************/
179 :
180 2730 : inline GIntBig ReadVarInt64(const GByte **ppabyData)
181 : {
182 2730 : return static_cast<GIntBig>(ReadVarUInt64(ppabyData));
183 : }
184 :
185 : #define READ_VARINT64(pabyData, pabyDataLimit, nVal) \
186 : { \
187 : nVal = ReadVarInt64(&pabyData); \
188 : if (CHECK_OOB && pabyData > pabyDataLimit) \
189 : THROW_GPB_EXCEPTION; \
190 : }
191 :
192 : /************************************************************************/
193 : /* DecodeSInt() */
194 : /************************************************************************/
195 :
196 27458 : inline GIntBig DecodeSInt(GUIntBig nVal)
197 : {
198 27458 : return ((nVal & 1) == 0) ? static_cast<GIntBig>(nVal >> 1)
199 27458 : : -static_cast<GIntBig>(nVal >> 1) - 1;
200 : }
201 :
202 711759 : inline GInt32 DecodeSInt(GUInt32 nVal)
203 : {
204 711759 : return ((nVal & 1) == 0) ? static_cast<GInt32>(nVal >> 1)
205 711759 : : -static_cast<GInt32>(nVal >> 1) - 1;
206 : }
207 :
208 : /************************************************************************/
209 : /* ReadVarSInt64() */
210 : /************************************************************************/
211 :
212 27458 : inline GIntBig ReadVarSInt64(const GByte **ppabyPtr)
213 : {
214 27458 : return DecodeSInt(ReadVarUInt64(ppabyPtr));
215 : }
216 :
217 : #define READ_VARSINT64(pabyData, pabyDataLimit, nVal) \
218 : { \
219 : nVal = ReadVarSInt64(&pabyData); \
220 : if (CHECK_OOB && pabyData > pabyDataLimit) \
221 : THROW_GPB_EXCEPTION; \
222 : }
223 :
224 : #define READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nVal) \
225 : { \
226 : nVal = ReadVarSInt64(&pabyData); \
227 : }
228 :
229 : /************************************************************************/
230 : /* ReadVarInt32() */
231 : /************************************************************************/
232 :
233 129072 : inline int ReadVarInt32(const GByte **ppabyData)
234 : {
235 : /* If you use int32 or int64 as the type for a negative number, */
236 : /* the resulting varint is always ten bytes long */
237 129072 : GIntBig nVal = static_cast<GIntBig>(ReadVarUInt64(ppabyData));
238 129072 : return static_cast<int>(nVal);
239 : }
240 :
241 : #define READ_VARINT32(pabyData, pabyDataLimit, nVal) \
242 : { \
243 : nVal = ReadVarInt32(&pabyData); \
244 : if (CHECK_OOB && pabyData > pabyDataLimit) \
245 : THROW_GPB_EXCEPTION; \
246 : }
247 :
248 : #define READ_VARSINT32(pabyData, pabyDataLimit, nVal) \
249 : { \
250 : nVal = DecodeSInt(static_cast<GUInt32>(ReadVarUInt64(&pabyData))); \
251 : if (CHECK_OOB && pabyData > pabyDataLimit) \
252 : THROW_GPB_EXCEPTION; \
253 : }
254 :
255 : /************************************************************************/
256 : /* ReadFloat32() */
257 : /************************************************************************/
258 :
259 623 : inline float ReadFloat32(const GByte **ppabyData, const GByte *pabyDataLimit)
260 : {
261 623 : if (*ppabyData + sizeof(float) > pabyDataLimit)
262 0 : THROW_GPB_EXCEPTION;
263 : float fValue;
264 623 : memcpy(&fValue, *ppabyData, sizeof(float));
265 623 : CPL_LSBPTR32(&fValue);
266 623 : *ppabyData += sizeof(float);
267 623 : return fValue;
268 : }
269 :
270 : /************************************************************************/
271 : /* ReadFloat64() */
272 : /************************************************************************/
273 :
274 1519 : inline double ReadFloat64(const GByte **ppabyData, const GByte *pabyDataLimit)
275 : {
276 1519 : if (*ppabyData + sizeof(double) > pabyDataLimit)
277 0 : THROW_GPB_EXCEPTION;
278 : double dfValue;
279 1519 : memcpy(&dfValue, *ppabyData, sizeof(double));
280 1519 : CPL_LSBPTR64(&dfValue);
281 1519 : *ppabyData += sizeof(double);
282 1519 : return dfValue;
283 : }
284 :
285 : /************************************************************************/
286 : /* SkipVarInt() */
287 : /************************************************************************/
288 :
289 24052 : inline void SkipVarInt(const GByte **ppabyData)
290 : {
291 24052 : const GByte *pabyData = *ppabyData;
292 : while (true)
293 : {
294 27547 : int nByte = *pabyData;
295 27547 : if (!(nByte & 0x80))
296 : {
297 24052 : *ppabyData = pabyData + 1;
298 24052 : return;
299 : }
300 3495 : pabyData++;
301 3495 : }
302 : }
303 :
304 : #define SKIP_VARINT(pabyData, pabyDataLimit) \
305 : { \
306 : SkipVarInt(&pabyData); \
307 : if (CHECK_OOB && pabyData > pabyDataLimit) \
308 : THROW_GPB_EXCEPTION; \
309 : }
310 :
311 : #define READ_FIELD_KEY(nKey) READ_VARINT32(pabyData, pabyDataLimit, nKey)
312 :
313 : #define READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength) \
314 : do \
315 : { \
316 : READ_SIZE(pabyData, pabyDataLimit, l_nDataLength); \
317 : pszTxt = (char *)VSI_MALLOC_VERBOSE(l_nDataLength + 1); \
318 : if (pszTxt == nullptr) \
319 : THROW_GPB_EXCEPTION; \
320 : memcpy(pszTxt, pabyData, l_nDataLength); \
321 : pszTxt[l_nDataLength] = 0; \
322 : pabyData += l_nDataLength; \
323 : } while (0)
324 :
325 : #define READ_TEXT(pabyData, pabyDataLimit, pszTxt) \
326 : do \
327 : { \
328 : unsigned int l_nDataLength; \
329 : READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength); \
330 : } while (0)
331 :
332 : /************************************************************************/
333 : /* SkipUnknownField() */
334 : /************************************************************************/
335 :
336 : #define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose) \
337 : int nWireType = GET_WIRETYPE(nKey); \
338 : if (verbose) \
339 : { \
340 : int nFieldNumber = GET_FIELDNUMBER(nKey); \
341 : CPLDebug("PBF", "Unhandled case: nFieldNumber = %d, nWireType = %d", \
342 : nFieldNumber, nWireType); \
343 : } \
344 : switch (nWireType) \
345 : { \
346 : case WT_VARINT: \
347 : { \
348 : SKIP_VARINT(pabyData, pabyDataLimit); \
349 : break; \
350 : } \
351 : case WT_64BIT: \
352 : { \
353 : if (CHECK_OOB && pabyDataLimit - pabyData < 8) \
354 : THROW_GPB_EXCEPTION; \
355 : pabyData += 8; \
356 : break; \
357 : } \
358 : case WT_DATA: \
359 : { \
360 : unsigned int nDataLength; \
361 : READ_SIZE(pabyData, pabyDataLimit, nDataLength); \
362 : pabyData += nDataLength; \
363 : break; \
364 : } \
365 : case WT_32BIT: \
366 : { \
367 : if (CHECK_OOB && pabyDataLimit - pabyData < 4) \
368 : THROW_GPB_EXCEPTION; \
369 : pabyData += 4; \
370 : break; \
371 : } \
372 : default: \
373 : THROW_GPB_EXCEPTION; \
374 : }
375 :
376 76044 : inline int SkipUnknownField(int nKey, const GByte *pabyData,
377 : const GByte *pabyDataLimit, int verbose)
378 : {
379 76044 : const GByte *pabyDataBefore = pabyData;
380 : try
381 : {
382 76044 : SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
383 76044 : return static_cast<int>(pabyData - pabyDataBefore);
384 : }
385 0 : catch (const GPBException &e)
386 : {
387 0 : if (verbose)
388 : {
389 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
390 : }
391 0 : return -1;
392 : }
393 : }
394 :
395 : #define SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, verbose) \
396 : { \
397 : int _nOffset = \
398 : SkipUnknownField(nKey, pabyData, pabyDataLimit, verbose); \
399 : if (_nOffset < 0) \
400 : THROW_GPB_EXCEPTION; \
401 : pabyData += _nOffset; \
402 : }
403 :
404 : /************************************************************************/
405 : /* GetVarUIntSize() */
406 : /************************************************************************/
407 :
408 111039 : inline int GetVarUIntSize(GUIntBig nVal)
409 : {
410 111039 : int nBytes = 1;
411 121731 : while (nVal > 127)
412 : {
413 10692 : nBytes++;
414 10692 : nVal >>= 7;
415 : }
416 111039 : return nBytes;
417 : }
418 :
419 : /************************************************************************/
420 : /* EncodeSInt() */
421 : /************************************************************************/
422 :
423 133 : inline GUIntBig EncodeSInt(GIntBig nVal)
424 : {
425 133 : if (nVal < 0)
426 126 : return (static_cast<GUIntBig>(-(nVal + 1)) << 1) | 1;
427 : else
428 7 : return static_cast<GUIntBig>(nVal) << 1;
429 : }
430 :
431 5878 : inline GUInt32 EncodeSInt(GInt32 nVal)
432 : {
433 5878 : if (nVal < 0)
434 727 : return (static_cast<GUInt32>(-(nVal + 1)) << 1) | 1;
435 : else
436 5151 : return static_cast<GUInt32>(nVal) << 1;
437 : }
438 :
439 : /************************************************************************/
440 : /* GetVarIntSize() */
441 : /************************************************************************/
442 :
443 8 : inline int GetVarIntSize(GIntBig nVal)
444 : {
445 8 : return GetVarUIntSize(static_cast<GUIntBig>(nVal));
446 : }
447 :
448 : /************************************************************************/
449 : /* GetVarSIntSize() */
450 : /************************************************************************/
451 :
452 98 : inline int GetVarSIntSize(GIntBig nVal)
453 : {
454 98 : return GetVarUIntSize(EncodeSInt(nVal));
455 : }
456 :
457 : /************************************************************************/
458 : /* WriteVarUInt() */
459 : /************************************************************************/
460 :
461 68539 : inline void WriteVarUInt(GByte **ppabyData, GUIntBig nVal)
462 : {
463 68539 : GByte *pabyData = *ppabyData;
464 74824 : while (nVal > 127)
465 : {
466 6285 : *pabyData = static_cast<GByte>((nVal & 0x7f) | 0x80);
467 6285 : pabyData++;
468 6285 : nVal >>= 7;
469 : }
470 68539 : *pabyData = static_cast<GByte>(nVal);
471 68539 : pabyData++;
472 68539 : *ppabyData = pabyData;
473 68539 : }
474 :
475 : /************************************************************************/
476 : /* WriteVarUIntSingleByte() */
477 : /************************************************************************/
478 :
479 46484 : inline void WriteVarUIntSingleByte(GByte **ppabyData, GUIntBig nVal)
480 : {
481 46484 : GByte *pabyData = *ppabyData;
482 46484 : CPLAssert(nVal < 128);
483 46484 : *pabyData = static_cast<GByte>(nVal);
484 46484 : pabyData++;
485 46484 : *ppabyData = pabyData;
486 46484 : }
487 :
488 : /************************************************************************/
489 : /* WriteVarInt() */
490 : /************************************************************************/
491 :
492 3 : inline void WriteVarInt(GByte **ppabyData, GIntBig nVal)
493 : {
494 3 : WriteVarUInt(ppabyData, static_cast<GUIntBig>(nVal));
495 3 : }
496 :
497 : /************************************************************************/
498 : /* WriteVarSInt() */
499 : /************************************************************************/
500 :
501 35 : inline void WriteVarSInt(GByte **ppabyData, GIntBig nVal)
502 : {
503 35 : WriteVarUInt(ppabyData, EncodeSInt(nVal));
504 35 : }
505 :
506 : /************************************************************************/
507 : /* WriteFloat32() */
508 : /************************************************************************/
509 :
510 51 : inline void WriteFloat32(GByte **ppabyData, float fVal)
511 : {
512 51 : CPL_LSBPTR32(&fVal);
513 51 : memcpy(*ppabyData, &fVal, sizeof(float));
514 51 : *ppabyData += sizeof(float);
515 51 : }
516 :
517 : /************************************************************************/
518 : /* WriteFloat64() */
519 : /************************************************************************/
520 :
521 1564 : inline void WriteFloat64(GByte **ppabyData, double dfVal)
522 : {
523 1564 : CPL_LSBPTR64(&dfVal);
524 1559 : memcpy(*ppabyData, &dfVal, sizeof(double));
525 1559 : *ppabyData += sizeof(double);
526 1559 : }
527 :
528 : /************************************************************************/
529 : /* GetTextSize() */
530 : /************************************************************************/
531 :
532 2 : inline int GetTextSize(const char *pszText)
533 : {
534 2 : size_t nTextSize = strlen(pszText);
535 2 : return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
536 : }
537 :
538 10697 : inline int GetTextSize(const std::string &osText)
539 : {
540 10697 : size_t nTextSize = osText.size();
541 10704 : return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
542 : }
543 :
544 : /************************************************************************/
545 : /* WriteText() */
546 : /************************************************************************/
547 :
548 1 : inline void WriteText(GByte **ppabyData, const char *pszText)
549 : {
550 1 : size_t nTextSize = strlen(pszText);
551 1 : WriteVarUInt(ppabyData, nTextSize);
552 1 : memcpy(*ppabyData, pszText, nTextSize);
553 1 : *ppabyData += nTextSize;
554 1 : }
555 :
556 10741 : inline void WriteText(GByte **ppabyData, const std::string &osText)
557 : {
558 10741 : size_t nTextSize = osText.size();
559 10718 : WriteVarUInt(ppabyData, nTextSize);
560 10726 : memcpy(*ppabyData, osText.c_str(), nTextSize);
561 10733 : *ppabyData += nTextSize;
562 10733 : }
563 :
564 : #endif /* GPB_H_INCLUDED */
|