MOS Source Code
Loading...
Searching...
No Matches
pb_common.c
Go to the documentation of this file.
1/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
2 *
3 * 2014 Petteri Aimonen <jpa@kapsi.fi>
4 */
5
6#include "pb_common.h"
7
8static bool load_descriptor_values(pb_field_iter_t *iter)
9{
10 uint32_t word0;
11 uint32_t data_offset;
12 int_least8_t size_offset;
13
14 if (iter->index >= iter->descriptor->field_count)
15 return false;
16
17 word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
18 iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
19
20 switch(word0 & 3)
21 {
22 case 0: {
23 /* 1-word format */
24 iter->array_size = 1;
25 iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
26 size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
27 data_offset = (word0 >> 16) & 0xFF;
28 iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
29 break;
30 }
31
32 case 1: {
33 /* 2-word format */
34 uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
35
36 iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
37 iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
38 size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
39 data_offset = word1 & 0xFFFF;
40 iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
41 break;
42 }
43
44 case 2: {
45 /* 4-word format */
46 uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
47 uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
48 uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
49
50 iter->array_size = (pb_size_t)(word0 >> 16);
51 iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
52 size_offset = (int_least8_t)(word1 & 0xFF);
53 data_offset = word2;
54 iter->data_size = (pb_size_t)word3;
55 break;
56 }
57
58 default: {
59 /* 8-word format */
60 uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
61 uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
62 uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
63 uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
64
65 iter->array_size = (pb_size_t)word4;
66 iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
67 size_offset = (int_least8_t)(word1 & 0xFF);
68 data_offset = word2;
69 iter->data_size = (pb_size_t)word3;
70 break;
71 }
72 }
73
74 if (!iter->message)
75 {
76 /* Avoid doing arithmetic on null pointers, it is undefined */
77 iter->pField = NULL;
78 iter->pSize = NULL;
79 }
80 else
81 {
82 iter->pField = (char*)iter->message + data_offset;
83
84 if (size_offset)
85 {
86 iter->pSize = (char*)iter->pField - size_offset;
87 }
88 else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
89 (PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
90 PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
91 {
92 /* Fixed count array */
93 iter->pSize = &iter->array_size;
94 }
95 else
96 {
97 iter->pSize = NULL;
98 }
99
100 if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
101 {
102 iter->pData = *(void**)iter->pField;
103 }
104 else
105 {
106 iter->pData = iter->pField;
107 }
108 }
109
110 if (PB_LTYPE_IS_SUBMSG(iter->type))
111 {
112 iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
113 }
114 else
115 {
116 iter->submsg_desc = NULL;
117 }
118
119 return true;
120}
121
122static void advance_iterator(pb_field_iter_t *iter)
123{
124 iter->index++;
125
126 if (iter->index >= iter->descriptor->field_count)
127 {
128 /* Restart */
129 iter->index = 0;
130 iter->field_info_index = 0;
131 iter->submessage_index = 0;
132 iter->required_field_index = 0;
133 }
134 else
135 {
136 /* Increment indexes based on previous field type.
137 * All field info formats have the following fields:
138 * - lowest 2 bits tell the amount of words in the descriptor (2^n words)
139 * - bits 2..7 give the lowest bits of tag number.
140 * - bits 8..15 give the field type.
141 */
142 uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
143 pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
144 pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
145
146 /* Add to fields.
147 * The cast to pb_size_t is needed to avoid -Wconversion warning.
148 * Because the data is is constants from generator, there is no danger of overflow.
149 */
150 iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
151 iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
152 iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
153 }
154}
155
156bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
157{
158 memset(iter, 0, sizeof(*iter));
159
160 iter->descriptor = desc;
161 iter->message = message;
162
163 return load_descriptor_values(iter);
164}
165
166bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
167{
168 const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
169 bool status;
170
171 uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
172 if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
173 {
174 /* For pointer extensions, the pointer is stored directly
175 * in the extension structure. This avoids having an extra
176 * indirection. */
177 status = pb_field_iter_begin(iter, msg, &extension->dest);
178 }
179 else
180 {
181 status = pb_field_iter_begin(iter, msg, extension->dest);
182 }
183
184 iter->pSize = &extension->found;
185 return status;
186}
187
188bool pb_field_iter_next(pb_field_iter_t *iter)
189{
190 advance_iterator(iter);
192 return iter->index != 0;
193}
194
195bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
196{
197 if (iter->tag == tag)
198 {
199 return true; /* Nothing to do, correct field already. */
200 }
201 else if (tag > iter->descriptor->largest_tag)
202 {
203 return false;
204 }
205 else
206 {
207 pb_size_t start = iter->index;
208 uint32_t fieldinfo;
209
210 if (tag < iter->tag)
211 {
212 /* Fields are in tag number order, so we know that tag is between
213 * 0 and our start position. Setting index to end forces
214 * advance_iterator() call below to restart from beginning. */
215 iter->index = iter->descriptor->field_count;
216 }
217
218 do
219 {
220 /* Advance iterator but don't load values yet */
221 advance_iterator(iter);
222
223 /* Do fast check for tag number match */
224 fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
225
226 if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
227 {
228 /* Good candidate, check further */
230
231 if (iter->tag == tag &&
232 PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
233 {
234 /* Found it */
235 return true;
236 }
237 }
238 } while (iter->index != start);
239
240 /* Searched all the way back to start, and found nothing. */
242 return false;
243 }
244}
245
246bool pb_field_iter_find_extension(pb_field_iter_t *iter)
247{
248 if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
249 {
250 return true;
251 }
252 else
253 {
254 pb_size_t start = iter->index;
255 uint32_t fieldinfo;
256
257 do
258 {
259 /* Advance iterator but don't load values yet */
260 advance_iterator(iter);
261
262 /* Do fast check for field type */
263 fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
264
265 if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
266 {
267 return load_descriptor_values(iter);
268 }
269 } while (iter->index != start);
270
271 /* Searched all the way back to start, and found nothing. */
273 return false;
274 }
275}
276
277static void *pb_const_cast(const void *p)
278{
279 /* Note: this casts away const, in order to use the common field iterator
280 * logic for both encoding and decoding. The cast is done using union
281 * to avoid spurious compiler warnings. */
282 union {
283 void *p1;
284 const void *p2;
285 } t;
286 t.p2 = p;
287 return t.p1;
288}
289
290bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
291{
292 return pb_field_iter_begin(iter, desc, pb_const_cast(message));
293}
294
295bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
296{
297 return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
298}
299
300bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
301{
302 if (field->data_size == sizeof(pb_callback_t))
303 {
304 pb_callback_t *pCallback = (pb_callback_t*)field->pData;
305
306 if (pCallback != NULL)
307 {
308 if (istream != NULL && pCallback->funcs.decode != NULL)
309 {
310 return pCallback->funcs.decode(istream, field, &pCallback->arg);
311 }
312
313 if (ostream != NULL && pCallback->funcs.encode != NULL)
314 {
315 return pCallback->funcs.encode(ostream, field, &pCallback->arg);
316 }
317 }
318 }
319
320 return true; /* Success, but didn't do anything */
321
322}
323
324#ifdef PB_VALIDATE_UTF8
325
326/* This function checks whether a string is valid UTF-8 text.
327 *
328 * Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
329 * Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
330 * Licensed under "Short code license", which allows use under MIT license or
331 * any compatible with it.
332 */
333
334bool pb_validate_utf8(const char *str)
335{
336 const pb_byte_t *s = (const pb_byte_t*)str;
337 while (*s)
338 {
339 if (*s < 0x80)
340 {
341 /* 0xxxxxxx */
342 s++;
343 }
344 else if ((s[0] & 0xe0) == 0xc0)
345 {
346 /* 110XXXXx 10xxxxxx */
347 if ((s[1] & 0xc0) != 0x80 ||
348 (s[0] & 0xfe) == 0xc0) /* overlong? */
349 return false;
350 else
351 s += 2;
352 }
353 else if ((s[0] & 0xf0) == 0xe0)
354 {
355 /* 1110XXXX 10Xxxxxx 10xxxxxx */
356 if ((s[1] & 0xc0) != 0x80 ||
357 (s[2] & 0xc0) != 0x80 ||
358 (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
359 (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
360 (s[0] == 0xef && s[1] == 0xbf &&
361 (s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
362 return false;
363 else
364 s += 3;
365 }
366 else if ((s[0] & 0xf8) == 0xf0)
367 {
368 /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
369 if ((s[1] & 0xc0) != 0x80 ||
370 (s[2] & 0xc0) != 0x80 ||
371 (s[3] & 0xc0) != 0x80 ||
372 (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
373 (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
374 return false;
375 else
376 s += 4;
377 }
378 else
379 {
380 return false;
381 }
382 }
383
384 return true;
385}
386
387#endif
388
MOSAPI void(1, 2) fatal_abort(const char *fmt
#define PB_HTYPE(x)
Definition pb.h:298
uint_least8_t pb_byte_t
Definition pb.h:227
#define PB_LTYPE_EXTENSION
Definition pb.h:268
#define PB_ATYPE_STATIC
Definition pb.h:292
uint_least16_t pb_size_t
Definition pb.h:310
#define PB_ATYPE_POINTER
Definition pb.h:293
#define PB_HTYPE_REQUIRED
Definition pb.h:282
#define PB_ATYPE(x)
Definition pb.h:297
pb_field_iter_t pb_field_t
Definition pb.h:359
#define PB_LTYPE(x)
Definition pb.h:299
#define PB_HTYPE_REPEATED
Definition pb.h:285
#define PB_LTYPE_IS_SUBMSG(x)
Definition pb.h:300
#define PB_PROGMEM_READU32(x)
Definition pb.h:155
pb_byte_t pb_type_t
Definition pb.h:234
static bool load_descriptor_values(pb_field_iter_t *iter)
Definition pb_common.c:8
bool pb_field_iter_next(pb_field_iter_t *iter)
Definition pb_common.c:188
bool pb_field_iter_find_extension(pb_field_iter_t *iter)
Definition pb_common.c:246
bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
Definition pb_common.c:300
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
Definition pb_common.c:166
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
Definition pb_common.c:295
static void * pb_const_cast(const void *p)
Definition pb_common.c:277
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
Definition pb_common.c:156
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
Definition pb_common.c:195
static void advance_iterator(pb_field_iter_t *iter)
Definition pb_common.c:122
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
Definition pb_common.c:290
#define NULL
Definition pb_syshdr.h:46
unsigned int uint32_t
Definition pb_syshdr.h:24
static void * memset(void *s, int c, size_t n)
Definition pb_syshdr.h:101
int8_t int_least8_t
Definition pb_syshdr.h:30