1 /* pb_decode.c -- decode a protobuf using minimal resources
3 * 2011 Petteri Aimonen <jpa@kapsi.fi>
10 const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
11 (pb_decoder_t)&pb_dec_varint,
12 (pb_decoder_t)&pb_dec_svarint,
13 (pb_decoder_t)&pb_dec_fixed,
15 (pb_decoder_t)&pb_dec_bytes,
16 (pb_decoder_t)&pb_dec_string,
17 (pb_decoder_t)&pb_dec_submessage
24 bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
26 if (stream->bytes_left < count)
29 if (!stream->callback(stream, buf, count))
32 stream->bytes_left -= count;
36 static bool buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
38 uint8_t *source = (uint8_t*)stream->state;
41 memcpy(buf, source, count);
43 stream->state = source + count;
47 pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
50 stream.callback = &buf_read;
52 stream.bytes_left = bufsize;
60 bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
63 bool status = pb_decode_varint64(stream, &temp);
68 bool pb_decode_varint64(pb_istream_t *stream, uint64_t *dest)
74 while (bitpos < 64 && pb_read(stream, &byte, 1))
76 *dest |= (uint64_t)(byte & 0x7F) << bitpos;
86 bool pb_skip_varint(pb_istream_t *stream)
91 if (!pb_read(stream, &byte, 1))
93 } while (byte & 0x80);
97 bool pb_skip_string(pb_istream_t *stream)
100 if (!pb_decode_varint32(stream, &length))
103 return pb_read(stream, NULL, length);
106 /* Currently all wire type related stuff is kept hidden from
107 * callbacks. They shouldn't need it. It's better for performance
108 * to just assume the correct type and fail safely on corrupt message.
118 static bool skip(pb_istream_t *stream, int wire_type)
122 case WT_VARINT: return pb_skip_varint(stream);
123 case WT_64BIT: return pb_read(stream, NULL, 8);
124 case WT_STRING: return pb_skip_string(stream);
125 case WT_32BIT: return pb_read(stream, NULL, 4);
126 default: return false;
130 /* Read a raw value to buffer, for the purpose of passing it to callback.
131 * Size is maximum size on call, and actual size on return. */
132 static bool read_raw_value(pb_istream_t *stream, int wire_type, uint8_t *buf, size_t *size)
134 size_t max_size = *size;
142 if (*size > max_size) return false;
143 if (!pb_read(stream, buf, 1)) return false;
144 } while (*buf++ & 0x80);
149 return pb_read(stream, buf, 8);
153 return pb_read(stream, buf, 4);
155 default: return false;
159 /* Decode string length from stream and return a substream with limited length */
160 static bool make_string_substream(pb_istream_t *stream, pb_istream_t *substream)
163 if (!pb_decode_varint32(stream, &size))
166 *substream = *stream;
167 if (substream->bytes_left < size)
170 substream->bytes_left = size;
171 stream->bytes_left -= size;
175 /* Iterator for pb_field_t list */
177 const pb_field_t *start;
178 const pb_field_t *current;
183 } pb_field_iterator_t;
185 static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct)
187 iter->start = iter->current = fields;
188 iter->field_index = 0;
189 iter->pData = dest_struct;
190 iter->dest_struct = dest_struct;
193 static bool pb_field_next(pb_field_iterator_t *iter)
195 bool notwrapped = true;
198 if (iter->current->tag == 0)
200 iter->current = iter->start;
201 iter->field_index = 0;
202 iter->pData = iter->dest_struct;
206 iter->pData = (char*)iter->pData + iter->current->data_offset;
207 iter->pSize = (char*)iter->pData + iter->current->size_offset;
211 static bool pb_field_find(pb_field_iterator_t *iter, int tag)
213 int start = iter->field_index;
216 if (iter->current->tag == tag)
219 } while (iter->field_index != start);
224 /*************************
225 * Decode a single field *
226 *************************/
228 bool decode_field(pb_istream_t *stream, int wire_type, pb_field_iterator_t *iter)
230 pb_decoder_t func = PB_DECODERS[PB_LTYPE(iter->current->type)];
232 switch (PB_HTYPE(iter->current->type))
234 case PB_HTYPE_REQUIRED:
235 return func(stream, iter->current, iter->pData);
237 case PB_HTYPE_OPTIONAL:
238 *(bool*)iter->pSize = true;
239 return func(stream, iter->current, iter->pData);
242 if (wire_type == WT_STRING
243 && PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE)
246 size_t *size = (size_t*)iter->pSize;
247 pb_istream_t substream;
248 if (!make_string_substream(stream, &substream))
251 while (substream.bytes_left && *size < iter->current->array_size)
253 void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
254 if (!func(stream, iter->current, pItem))
258 return (substream.bytes_left == 0);
263 size_t *size = (size_t*)iter->pSize;
264 void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
265 if (*size >= iter->current->array_size)
269 return func(stream, iter->current, pItem);
272 case PB_HTYPE_CALLBACK:
273 if (wire_type == WT_STRING)
275 pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
276 pb_istream_t substream;
278 if (!make_string_substream(stream, &substream))
281 while (substream.bytes_left)
283 if (!pCallback->funcs.decode(&substream, iter->current, pCallback->arg))
290 /* Copy the single scalar value to stack.
291 * This is required so that we can limit the stream length,
292 * which in turn allows to use same callback for packed and
293 * not-packed fields. */
294 pb_istream_t substream;
295 pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
297 size_t size = sizeof(buffer);
299 if (!read_raw_value(stream, wire_type, buffer, &size))
301 substream = pb_istream_from_buffer(buffer, size);
303 return pCallback->funcs.decode(&substream, iter->current, pCallback->arg);
311 /*********************
312 * Decode all fields *
313 *********************/
315 bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
317 uint32_t fields_seen = 0; /* Used to check for required fields */
318 pb_field_iterator_t iter;
321 if (fields[0].tag == 0)
323 /* No fields -> nothing to do */
324 return pb_read(stream, NULL, stream->bytes_left);
327 pb_field_init(&iter, fields, dest_struct);
329 /* Initialize size/has fields and apply default values */
332 if (PB_HTYPE(iter.current->type) == PB_HTYPE_OPTIONAL)
334 *(bool*)iter.pSize = false;
336 /* Initialize to default value */
337 if (iter.current->ptr != NULL)
338 memcpy(iter.pData, iter.current->ptr, iter.current->data_size);
340 memset(iter.pData, 0, iter.current->data_size);
342 else if (PB_HTYPE(iter.current->type) == PB_HTYPE_ARRAY)
344 *(size_t*)iter.pSize = 0;
346 } while (pb_field_next(&iter));
348 while (stream->bytes_left)
352 if (!pb_decode_varint32(stream, &temp))
356 wire_type = temp & 7;
358 if (!pb_field_find(&iter, tag))
360 /* No match found, skip data */
361 skip(stream, wire_type);
365 fields_seen |= 1 << (iter.field_index & 31);
367 if (!decode_field(stream, wire_type, &iter))
371 /* Check that all required fields (mod 31) were present. */
372 for (i = 0; fields[i].tag != 0; i++)
374 if (PB_HTYPE(fields[i].type) == PB_HTYPE_REQUIRED &&
375 !(fields_seen & (1 << (i & 31))))
386 /* Copy destsize bytes from src so that values are casted properly.
387 * On little endian machine, copy first n bytes of src
388 * On big endian machine, copy last n bytes of src
389 * srcsize must always be larger than destsize
391 static void endian_copy(void *dest, void *src, size_t destsize, size_t srcsize)
393 #ifdef __BIG_ENDIAN__
394 memcpy(dest, (char*)src + (srcsize - destsize), destsize);
396 memcpy(dest, src, destsize);
400 bool pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
403 bool status = pb_decode_varint64(stream, &temp);
404 endian_copy(dest, &temp, field->data_size, sizeof(temp));
408 bool pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
411 bool status = pb_decode_varint64(stream, &temp);
412 temp = (temp >> 1) ^ -(int64_t)(temp & 1);
413 endian_copy(dest, &temp, field->data_size, sizeof(temp));
417 bool pb_dec_fixed(pb_istream_t *stream, const pb_field_t *field, void *dest)
419 #ifdef __BIG_ENDIAN__
420 uint8_t bytes[8] = {0};
421 bool status = pb_read(stream, bytes, field->data_size);
422 uint8_t lebytes[8] = {bytes[7], bytes[6], bytes[5], bytes[4],
423 bytes[3], bytes[2], bytes[1], bytes[0]};
424 endian_copy(dest, lebytes, field->data_size, 8);
427 return pb_read(stream, (uint8_t*)dest, field->data_size);
431 bool pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, uint8_t *dest)
433 pb_bytes_array_t *x = (pb_bytes_array_t*)dest;
436 if (!pb_decode_varint32(stream, &temp))
440 /* Note: data_size includes the size of the x.size field, too.
441 * Calculate actual size starting from offset. */
442 if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
445 return pb_read(stream, x->bytes, x->size);
448 bool pb_dec_string(pb_istream_t *stream, const pb_field_t *field, uint8_t *dest)
452 if (!pb_decode_varint32(stream, &size))
455 if (size > field->data_size - 1)
458 status = pb_read(stream, (uint8_t*)dest, size);
459 *((uint8_t*)dest + size) = 0;
463 bool pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
465 pb_istream_t substream;
467 if (!make_string_substream(stream, &substream))
470 if (field->ptr == NULL)
473 return pb_decode(&substream, (pb_field_t*)field->ptr, dest);