static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
{
uint8_t byte;
- int bitpos = 0;
- *dest = 0;
+ uint32_t result;
- while (bitpos < 32 && pb_read(stream, &byte, 1))
+ if (!pb_read(stream, &byte, 1))
+ return false;
+
+ if (!(byte & 0x80))
{
- *dest |= (uint32_t)(byte & 0x7F) << bitpos;
- bitpos += 7;
-
- if (!(byte & 0x80))
- return true;
+ /* Quick case, 1 byte value */
+ result = byte;
}
-
- PB_RETURN_ERROR(stream, "varint overflow");
+ else
+ {
+ /* Multibyte case */
+ uint8_t bitpos = 7;
+ result = byte & 0x7F;
+
+ do
+ {
+ if (bitpos >= 32)
+ PB_RETURN_ERROR(stream, "varint overflow");
+
+ if (!pb_read(stream, &byte, 1))
+ return false;
+
+ result |= (uint32_t)(byte & 0x7F) << bitpos;
+ bitpos = (uint8_t)(bitpos + 7);
+ } while (byte & 0x80);
+ }
+
+ *dest = result;
+ return true;
}
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
{
uint8_t byte;
- int bitpos = 0;
- *dest = 0;
+ uint8_t bitpos = 0;
+ uint64_t result = 0;
- while (bitpos < 64 && pb_read(stream, &byte, 1))
+ do
{
- *dest |= (uint64_t)(byte & 0x7F) << bitpos;
- bitpos += 7;
+ if (bitpos >= 64)
+ PB_RETURN_ERROR(stream, "varint overflow");
- if (!(byte & 0x80))
- return true;
- }
+ if (!pb_read(stream, &byte, 1))
+ return false;
+
+ result |= (uint64_t)(byte & 0x7F) << bitpos;
+ bitpos = (uint8_t)(bitpos + 7);
+ } while (byte & 0x80);
- PB_RETURN_ERROR(stream, "varint overflow");
+ *dest = result;
+ return true;
}
bool checkreturn pb_skip_varint(pb_istream_t *stream)
typedef struct {
const pb_field_t *start; /* Start of the pb_field_t array */
const pb_field_t *current; /* Current position of the iterator */
- int field_index; /* Zero-based index of the field. */
- int required_field_index; /* Zero-based index that counts only the required fields */
+ unsigned field_index; /* Zero-based index of the field. */
+ unsigned required_field_index; /* Zero-based index that counts only the required fields */
void *dest_struct; /* Pointer to the destination structure to decode to */
void *pData; /* Pointer where to store current field value */
void *pSize; /* Pointer where to store the size of current array field */
bool notwrapped = true;
size_t prev_size = iter->current->data_size;
- if (PB_HTYPE(iter->current->type) == PB_HTYPE_ARRAY)
+ if (PB_ATYPE(iter->current->type) == PB_ATYPE_STATIC &&
+ PB_HTYPE(iter->current->type) == PB_HTYPE_REPEATED)
+ {
prev_size *= iter->current->array_size;
+ }
if (PB_HTYPE(iter->current->type) == PB_HTYPE_REQUIRED)
iter->required_field_index++;
static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag)
{
- int start = iter->field_index;
+ unsigned start = iter->field_index;
do {
if (iter->current->tag == tag)
* Decode a single field *
*************************/
-static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
+static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{
- pb_decoder_t func = PB_DECODERS[PB_LTYPE(iter->current->type)];
+ pb_type_t type;
+ pb_decoder_t func;
- switch (PB_HTYPE(iter->current->type))
+ type = iter->current->type;
+ func = PB_DECODERS[PB_LTYPE(type)];
+
+ switch (PB_HTYPE(type))
{
case PB_HTYPE_REQUIRED:
return func(stream, iter->current, iter->pData);
*(bool*)iter->pSize = true;
return func(stream, iter->current, iter->pData);
- case PB_HTYPE_ARRAY:
+ case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
- && PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE)
+ && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Packed array */
- bool status;
+ bool status = true;
size_t *size = (size_t*)iter->pSize;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
{
void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
if (!func(&substream, iter->current, pItem))
- return false;
+ {
+ status = false;
+ break;
+ }
(*size)++;
}
- status = (substream.bytes_left == 0);
pb_close_string_substream(stream, &substream);
+
+ if (substream.bytes_left != 0)
+ PB_RETURN_ERROR(stream, "array overflow");
+
return status;
}
else
(*size)++;
return func(stream, iter->current, pItem);
}
+
+ default:
+ PB_RETURN_ERROR(stream, "invalid field type");
+ }
+}
+
+static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
+{
+ pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
+
+ if (pCallback->funcs.decode == NULL)
+ return pb_skip_field(stream, wire_type);
+
+ if (wire_type == PB_WT_STRING)
+ {
+ pb_istream_t substream;
+
+ if (!pb_make_string_substream(stream, &substream))
+ return false;
- case PB_HTYPE_CALLBACK:
+ while (substream.bytes_left)
{
- pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
-
- if (pCallback->funcs.decode == NULL)
- return pb_skip_field(stream, wire_type);
-
- if (wire_type == PB_WT_STRING)
- {
- pb_istream_t substream;
-
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- while (substream.bytes_left)
- {
- if (!pCallback->funcs.decode(&substream, iter->current, pCallback->arg))
- PB_RETURN_ERROR(stream, "callback failed");
- }
-
- pb_close_string_substream(stream, &substream);
- return true;
- }
- else
- {
- /* Copy the single scalar value to stack.
- * This is required so that we can limit the stream length,
- * which in turn allows to use same callback for packed and
- * not-packed fields. */
- pb_istream_t substream;
- uint8_t buffer[10];
- size_t size = sizeof(buffer);
-
- if (!read_raw_value(stream, wire_type, buffer, &size))
- return false;
- substream = pb_istream_from_buffer(buffer, size);
-
- return pCallback->funcs.decode(&substream, iter->current, pCallback->arg);
- }
+ if (!pCallback->funcs.decode(&substream, iter->current, pCallback->arg))
+ PB_RETURN_ERROR(stream, "callback failed");
}
+ pb_close_string_substream(stream, &substream);
+ return true;
+ }
+ else
+ {
+ /* Copy the single scalar value to stack.
+ * This is required so that we can limit the stream length,
+ * which in turn allows to use same callback for packed and
+ * not-packed fields. */
+ pb_istream_t substream;
+ uint8_t buffer[10];
+ size_t size = sizeof(buffer);
+
+ if (!read_raw_value(stream, wire_type, buffer, &size))
+ return false;
+ substream = pb_istream_from_buffer(buffer, size);
+
+ return pCallback->funcs.decode(&substream, iter->current, pCallback->arg);
+ }
+}
+
+static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
+{
+ switch (PB_ATYPE(iter->current->type))
+ {
+ case PB_ATYPE_STATIC:
+ return decode_static_field(stream, wire_type, iter);
+
+ case PB_ATYPE_CALLBACK:
+ return decode_callback_field(stream, wire_type, iter);
+
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
/* Initialize size/has fields and apply default values */
do
{
+ pb_type_t type;
+ type = iter.current->type;
+
if (iter.current->tag == 0)
continue;
- /* Initialize the size field for optional/repeated fields to 0. */
- if (PB_HTYPE(iter.current->type) == PB_HTYPE_OPTIONAL)
- {
- *(bool*)iter.pSize = false;
- }
- else if (PB_HTYPE(iter.current->type) == PB_HTYPE_ARRAY)
+ if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{
- *(size_t*)iter.pSize = 0;
- continue; /* Array is empty, no need to initialize contents */
+ /* Initialize the size field for optional/repeated fields to 0. */
+ if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL)
+ {
+ *(bool*)iter.pSize = false;
+ }
+ else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
+ {
+ *(size_t*)iter.pSize = 0;
+ continue; /* Array is empty, no need to initialize contents */
+ }
+
+ /* Initialize field contents to default value */
+ if (PB_LTYPE(iter.current->type) == PB_LTYPE_SUBMESSAGE)
+ {
+ pb_message_set_to_defaults((const pb_field_t *) iter.current->ptr, iter.pData);
+ }
+ else if (iter.current->ptr != NULL)
+ {
+ memcpy(iter.pData, iter.current->ptr, iter.current->data_size);
+ }
+ else
+ {
+ memset(iter.pData, 0, iter.current->data_size);
+ }
}
-
- /* Initialize field contents to default value */
- if (PB_HTYPE(iter.current->type) == PB_HTYPE_CALLBACK)
+ else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
{
continue; /* Don't overwrite callback */
}
- else if (PB_LTYPE(iter.current->type) == PB_LTYPE_SUBMESSAGE)
- {
- pb_message_set_to_defaults((const pb_field_t *) iter.current->ptr, iter.pData);
- }
- else if (iter.current->ptr != NULL)
- {
- memcpy(iter.pData, iter.current->ptr, iter.current->data_size);
- }
- else
- {
- memset(iter.pData, 0, iter.current->data_size);
- }
} while (pb_field_next(&iter));
}
* seeking to the end of the field array. Usually we
* are already close to end after decoding.
*/
- int req_field_count;
- uint8_t last_type;
- int i;
+ unsigned req_field_count;
+ pb_type_t last_type;
+ unsigned i;
do {
req_field_count = iter.required_field_index;
last_type = iter.current->type;
/* New array entries need to be initialized, while required and optional
* submessages have already been initialized in the top-level pb_decode. */
- if (PB_HTYPE(field->type) == PB_HTYPE_ARRAY)
+ if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
status = pb_decode(&substream, submsg_fields, dest);
else
status = pb_decode_noinit(&substream, submsg_fields, dest);