1 : /******************************************************************************
2 : * $Id: gpb.h 24707 2012-07-24 21:54:42Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
6 : * Purpose: Google Protocol Buffer generic handling functions
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2012, Even Rouault, <even dot rouault at mines dash paris dot org>
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 :
36 : #ifndef CHECK_OOB
37 : #define CHECK_OOB 1
38 : #endif
39 :
40 : //#define DEBUG_GPB_ERRORS
41 : #ifdef DEBUG_GPB_ERRORS
42 : static void error_occured(int nLine)
43 : {
44 : CPLError(CE_Failure, CPLE_AppDefined, "Parsing error occured at line %d", nLine);
45 : }
46 :
47 : #define GOTO_END_ERROR do { error_occured(__LINE__); goto end_error; } while(0)
48 : #else
49 : #define GOTO_END_ERROR goto end_error
50 : #endif
51 :
52 : #if defined(__GNUC__)
53 : #define CPL_NO_INLINE __attribute__ ((noinline))
54 : #else
55 : #define CPL_NO_INLINE
56 : #endif
57 :
58 : /************************************************************************/
59 : /* Google Protocol Buffer definitions */
60 : /************************************************************************/
61 :
62 : #define WT_VARINT 0
63 : #define WT_64BIT 1
64 : #define WT_DATA 2
65 : #define WT_STARTGROUP 3
66 : #define WT_ENDGROUP 4
67 : #define WT_32BIT 5
68 :
69 : #define MAKE_KEY(nFieldNumber, nWireType) ((nFieldNumber << 3) | nWireType)
70 : #define GET_WIRETYPE(nKey) (nKey & 0x7)
71 : #define GET_FIELDNUMBER(nKey) (nKey >> 3)
72 :
73 : /************************************************************************/
74 : /* ReadVarInt32() */
75 : /************************************************************************/
76 :
77 5024 : static int ReadVarInt32(GByte** ppabyData)
78 : {
79 5024 : int nVal = 0;
80 5024 : int nShift = 0;
81 5024 : GByte* pabyData = *ppabyData;
82 :
83 114 : while(TRUE)
84 : {
85 5138 : int nByte = *pabyData;
86 5138 : if (!(nByte & 0x80))
87 : {
88 5024 : *ppabyData = pabyData + 1;
89 5024 : return nVal | (nByte << nShift);
90 : }
91 114 : nVal |= (nByte & 0x7f) << nShift;
92 114 : pabyData ++;
93 114 : nShift += 7;
94 : }
95 : }
96 :
97 : #define READ_VARINT32(pabyData, pabyDataLimit, nVal) \
98 : { \
99 : nVal = ReadVarInt32(&pabyData); \
100 : if (CHECK_OOB && pabyData > pabyDataLimit) GOTO_END_ERROR; \
101 : }
102 :
103 : #define READ_VARSINT32(pabyData, pabyDataLimit, nVal) \
104 : { \
105 : nVal = ReadVarInt32(&pabyData); \
106 : nVal = ((nVal & 1) == 0) ? (((unsigned int)nVal) >> 1) : -(((unsigned int)nVal) >> 1)-1; \
107 : if (CHECK_OOB && pabyData > pabyDataLimit) GOTO_END_ERROR; \
108 : }
109 :
110 : /************************************************************************/
111 : /* ReadVarUInt32() */
112 : /************************************************************************/
113 :
114 3572 : static unsigned int ReadVarUInt32(GByte** ppabyData)
115 : {
116 3572 : unsigned int nVal = 0;
117 3572 : int nShift = 0;
118 3572 : GByte* pabyData = *ppabyData;
119 :
120 228 : while(TRUE)
121 : {
122 3800 : int nByte = *pabyData;
123 3800 : if (!(nByte & 0x80))
124 : {
125 3572 : *ppabyData = pabyData + 1;
126 3572 : return nVal | (nByte << nShift);
127 : }
128 228 : nVal |= (nByte & 0x7f) << nShift;
129 228 : pabyData ++;
130 228 : nShift += 7;
131 : }
132 : }
133 :
134 : #define READ_VARUINT32(pabyData, pabyDataLimit, nVal) \
135 : { \
136 : nVal = ReadVarUInt32(&pabyData); \
137 : if (CHECK_OOB && pabyData > pabyDataLimit) GOTO_END_ERROR; \
138 : }
139 :
140 : #define READ_SIZE(pabyData, pabyDataLimit, nSize) \
141 : { \
142 : READ_VARUINT32(pabyData, pabyDataLimit, nSize); \
143 : if (CHECK_OOB && nSize > pabyDataLimit - pabyData) GOTO_END_ERROR; \
144 : }
145 :
146 : /************************************************************************/
147 : /* ReadVarInt64() */
148 : /************************************************************************/
149 :
150 2689 : static GIntBig ReadVarInt64(GByte** ppabyData)
151 : {
152 2689 : GIntBig nVal = 0;
153 2689 : int nShift = 0;
154 2689 : GByte* pabyData = *ppabyData;
155 :
156 2370 : while(TRUE)
157 : {
158 5059 : int nByte = *pabyData;
159 5059 : if (!(nByte & 0x80))
160 : {
161 2689 : *ppabyData = pabyData + 1;
162 2689 : return nVal | ((GIntBig)nByte << nShift);
163 : }
164 2370 : nVal |= ((GIntBig)(nByte & 0x7f)) << nShift;
165 2370 : pabyData ++;
166 2370 : nShift += 7;
167 : }
168 : }
169 :
170 : #define READ_VARINT64(pabyData, pabyDataLimit, nVal) \
171 : { \
172 : nVal = ReadVarInt64(&pabyData); \
173 : if (CHECK_OOB && pabyData > pabyDataLimit) GOTO_END_ERROR; \
174 : }
175 :
176 : #define READ_VARSINT64(pabyData, pabyDataLimit, nVal) \
177 : { \
178 : nVal = ReadVarInt64(&pabyData); \
179 : nVal = ((nVal & 1) == 0) ? (((GUIntBig)nVal) >> 1) : -(((GUIntBig)nVal) >> 1)-1; \
180 : if (CHECK_OOB && pabyData > pabyDataLimit) GOTO_END_ERROR; \
181 : }
182 :
183 : #define READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nVal) \
184 : { \
185 : nVal = ReadVarInt64(&pabyData); \
186 : nVal = ((nVal & 1) == 0) ? (((GUIntBig)nVal) >> 1) : -(((GUIntBig)nVal) >> 1)-1; \
187 : }
188 :
189 : /************************************************************************/
190 : /* SkipVarInt() */
191 : /************************************************************************/
192 :
193 38 : static void SkipVarInt(GByte** ppabyData)
194 : {
195 38 : GByte* pabyData = *ppabyData;
196 19 : while(TRUE)
197 : {
198 57 : int nByte = *pabyData;
199 57 : if (!(nByte & 0x80))
200 : {
201 38 : *ppabyData = pabyData + 1;
202 : return;
203 : }
204 19 : pabyData ++;
205 : }
206 : }
207 :
208 : #define SKIP_VARINT(pabyData, pabyDataLimit) \
209 : { \
210 : SkipVarInt(&pabyData); \
211 : if (CHECK_OOB && pabyData > pabyDataLimit) GOTO_END_ERROR; \
212 : }
213 :
214 : #define READ_FIELD_KEY(nKey) READ_VARINT32(pabyData, pabyDataLimit, nKey)
215 :
216 : #define READ_TEXT(pabyData, pabyDataLimit, pszTxt) \
217 : unsigned int nDataLength; \
218 : READ_SIZE(pabyData, pabyDataLimit, nDataLength); \
219 : pszTxt = (char*)VSIMalloc(nDataLength + 1); \
220 : if( pszTxt == NULL ) GOTO_END_ERROR; \
221 : memcpy(pszTxt, pabyData, nDataLength); \
222 : pszTxt[nDataLength] = 0; \
223 : pabyData += nDataLength;
224 :
225 : /************************************************************************/
226 : /* SkipUnkownField() */
227 : /************************************************************************/
228 :
229 : #define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose) \
230 : int nWireType = GET_WIRETYPE(nKey); \
231 : if (verbose) \
232 : { \
233 : int nFieldNumber = GET_FIELDNUMBER(nKey); \
234 : CPLDebug("PBF", "Unhandled case: nFieldNumber = %d, nWireType = %d\n", nFieldNumber, nWireType); \
235 : } \
236 : switch (nWireType) \
237 : { \
238 : case WT_VARINT: \
239 : { \
240 : SKIP_VARINT(pabyData, pabyDataLimit); \
241 : break; \
242 : } \
243 : case WT_64BIT: \
244 : { \
245 : if (CHECK_OOB && pabyDataLimit - pabyData < 8) GOTO_END_ERROR; \
246 : pabyData += 8; \
247 : break; \
248 : } \
249 : case WT_DATA: \
250 : { \
251 : unsigned int nDataLength; \
252 : READ_SIZE(pabyData, pabyDataLimit, nDataLength); \
253 : pabyData += nDataLength; \
254 : break; \
255 : } \
256 : case WT_32BIT: \
257 : { \
258 : if (CHECK_OOB && pabyDataLimit - pabyData < 4) GOTO_END_ERROR; \
259 : pabyData += 4; \
260 : break; \
261 : } \
262 : default: \
263 : GOTO_END_ERROR; \
264 : }
265 :
266 : static
267 : int SkipUnkownField(int nKey, GByte* pabyData, GByte* pabyDataLimit, int verbose) CPL_NO_INLINE;
268 :
269 : static
270 0 : int SkipUnkownField(int nKey, GByte* pabyData, GByte* pabyDataLimit, int verbose)
271 : {
272 0 : GByte* pabyDataBefore = pabyData;
273 0 : SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
274 0 : return pabyData - pabyDataBefore;
275 : end_error:
276 0 : return -1;
277 : }
278 :
279 : #define SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, verbose) \
280 : { \
281 : int _nOffset = SkipUnkownField(nKey, pabyData, pabyDataLimit, verbose); \
282 : if (_nOffset < 0) \
283 : GOTO_END_ERROR; \
284 : pabyData += _nOffset; \
285 : }
286 :
287 : #endif /* _GPB_H_INCLUDED */
|