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