* pb_istream *
**************/
-bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
+static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
- if (stream->bytes_left < count)
- PB_RETURN_ERROR(stream, "end-of-stream");
+ uint8_t *source = (uint8_t*)stream->state;
+ stream->state = source + count;
- if (!stream->callback(stream, buf, count))
- PB_RETURN_ERROR(stream, "io error");
+ if (buf != NULL)
+ {
+ while (count--)
+ *buf++ = *source++;
+ }
- stream->bytes_left -= count;
return true;
}
-static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
+bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
- uint8_t *source = (uint8_t*)stream->state;
+#ifndef PB_BUFFER_ONLY
+ if (buf == NULL && stream->callback != buf_read)
+ {
+ /* Skip input bytes */
+ uint8_t tmp[16];
+ while (count > 16)
+ {
+ if (!pb_read(stream, tmp, 16))
+ return false;
+
+ count -= 16;
+ }
+
+ return pb_read(stream, tmp, count);
+ }
+#endif
+
+ if (stream->bytes_left < count)
+ PB_RETURN_ERROR(stream, "end-of-stream");
- if (buf != NULL)
- memcpy(buf, source, count);
+#ifndef PB_BUFFER_ONLY
+ if (!stream->callback(stream, buf, count))
+ PB_RETURN_ERROR(stream, "io error");
+#else
+ if (!buf_read(stream, buf, count))
+ return false;
+#endif
- stream->state = source + count;
+ stream->bytes_left -= count;
return true;
}
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
{
pb_istream_t stream;
+#ifdef PB_BUFFER_ONLY
+ stream.callback = NULL;
+#else
stream.callback = &buf_read;
+#endif
stream.state = buf;
stream.bytes_left = bufsize;
+#ifndef PB_NO_ERRMSG
+ stream.errmsg = NULL;
+#endif
return stream;
}
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
{
- uint64_t temp;
- bool status = pb_decode_varint(stream, &temp);
- *dest = (uint32_t)temp;
- return status;
+ uint8_t byte;
+ uint32_t result;
+
+ if (!pb_read(stream, &byte, 1))
+ return false;
+
+ if (!(byte & 0x80))
+ {
+ /* Quick case, 1 byte value */
+ result = byte;
+ }
+ 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;
uint8_t bitpos = 0;
- *dest = 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)
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
{
stream->state = substream->state;
+
+#ifndef PB_NO_ERRMSG
+ stream->errmsg = substream->errmsg;
+#endif
}
/* Iterator for pb_field_t list */
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_HTYPE(iter->current->type) == PB_HTYPE_REPEATED)
prev_size *= iter->current->array_size;
if (PB_HTYPE(iter->current->type) == PB_HTYPE_REQUIRED)
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)
*(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)
{
/* 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
{
*(bool*)iter.pSize = false;
}
- else if (PB_HTYPE(iter.current->type) == PB_HTYPE_ARRAY)
+ else if (PB_HTYPE(iter.current->type) == PB_HTYPE_REPEATED)
{
*(size_t*)iter.pSize = 0;
continue; /* Array is empty, no need to initialize contents */
if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
{
- fields_seen[iter.required_field_index >> 3] |= 1 << (iter.required_field_index & 7);
+ fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7));
}
if (!decode_field(stream, wire_type, &iter))
}
/* Check that all required fields were present. */
- pb_field_init(&iter, fields, dest_struct);
- do {
- if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED &&
- iter.required_field_index < PB_MAX_REQUIRED_FIELDS &&
- !(fields_seen[iter.required_field_index >> 3] & (1 << (iter.required_field_index & 7))))
+ {
+ /* First figure out the number of required fields by
+ * seeking to the end of the field array. Usually we
+ * are already close to end after decoding.
+ */
+ unsigned req_field_count;
+ pb_type_t last_type;
+ unsigned i;
+ do {
+ req_field_count = iter.required_field_index;
+ last_type = iter.current->type;
+ } while (pb_field_next(&iter));
+
+ /* Fixup if last field was also required. */
+ if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED)
+ req_field_count++;
+
+ /* Check the whole bytes */
+ for (i = 0; i < (req_field_count >> 3); i++)
{
- PB_RETURN_ERROR(stream, "missing required field");
+ if (fields_seen[i] != 0xFF)
+ PB_RETURN_ERROR(stream, "missing required field");
}
- } while (pb_field_next(&iter));
+
+ /* Check the remaining bits */
+ if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7))))
+ PB_RETURN_ERROR(stream, "missing required field");
+ }
return true;
}
return false;
if (value & 1)
- *dest = ~(value >> 1);
+ *dest = (int64_t)(~(value >> 1));
else
- *dest = value >> 1;
+ *dest = (int64_t)(value >> 1);
return true;
}
switch (field->data_size)
{
- case 1: *(uint8_t*)dest = value; break;
- case 2: *(uint16_t*)dest = value; break;
- case 4: *(uint32_t*)dest = value; break;
+ case 1: *(uint8_t*)dest = (uint8_t)value; break;
+ case 2: *(uint16_t*)dest = (uint16_t)value; break;
+ case 4: *(uint32_t*)dest = (uint32_t)value; break;
case 8: *(uint64_t*)dest = value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
switch (field->data_size)
{
- case 4: *(int32_t*)dest = value; break;
+ case 4: *(int32_t*)dest = (int32_t)value; break;
case 8: *(int64_t*)dest = value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
/* 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);