X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=pb_decode.c;h=9a48c60fcde5cede7467873c824962ef8501b002;hb=ba2ab9ea65d029b2560c461be317f3cf0d19eb3e;hp=a887d1558e4c322b83d6ba9ffd5d67a37b95b31f;hpb=eff9e11150c0bfb6baf5d6bec2351034b72d95ed;p=apps%2Fagl-service-can-low-level.git diff --git a/pb_decode.c b/pb_decode.c index a887d155..9a48c60f 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -13,7 +13,6 @@ #define checkreturn __attribute__((warn_unused_result)) #endif -#define NANOPB_INTERNALS #include "pb.h" #include "pb_decode.h" @@ -47,7 +46,8 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_exten static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn find_extension_field(pb_field_iterator_t *iter); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); -static bool pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); @@ -62,6 +62,7 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream); */ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { &pb_dec_varint, + &pb_dec_uvarint, &pb_dec_svarint, &pb_dec_fixed32, &pb_dec_fixed64, @@ -128,7 +129,7 @@ bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) * This is an optimization for the varint decoding. */ static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) { - if (!stream->bytes_left) + if (stream->bytes_left == 0) PB_RETURN_ERROR(stream, "end-of-stream"); #ifndef PB_BUFFER_ONLY @@ -172,7 +173,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) if (!pb_readbyte(stream, &byte)) return false; - if (!(byte & 0x80)) + if ((byte & 0x80) == 0) { /* Quick case, 1 byte value */ result = byte; @@ -357,6 +358,10 @@ static bool pb_field_next(pb_field_iterator_t *iter) { prev_size *= iter->pos->array_size; } + else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + prev_size = sizeof(void*); + } if (iter->pos->tag == 0) return false; /* Only happens with empty message types */ @@ -391,7 +396,7 @@ static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) { return true; } - pb_field_next(iter); + (void)pb_field_next(iter); } while (iter->field_index != start); return false; @@ -429,7 +434,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t if (!pb_make_string_substream(stream, &substream)) return false; - while (substream.bytes_left && *size < iter->pos->array_size) + while (substream.bytes_left > 0 && *size < iter->pos->array_size) { void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); if (!func(&substream, iter->pos, pItem)) @@ -463,6 +468,136 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t } } +#ifdef PB_ENABLE_MALLOC +/* Allocate storage for the field and store the pointer at iter->pData. + * array_size is the number of entries to reserve in an array. */ +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) +{ + void *ptr = *(void**)pData; + size_t size = array_size * data_size; + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, size); + if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) + { + *(void**)pItem = NULL; + } + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); + } +} +#endif + +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +{ +#ifndef PB_ENABLE_MALLOC + UNUSED(wire_type); + UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); +#else + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array, multiple items come in at once. */ + bool status = true; + size_t *size = (size_t*)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left) + { + if (*size + 1 > allocated_size) + { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) + { + status = false; + break; + } + } + + /* Decode the array entry */ + pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size); + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + pb_close_string_substream(stream, &substream); + + return status; + } + else + { + /* Normal repeated field, i.e. only one item at a time. */ + size_t *size = (size_t*)iter->pSize; + void *pItem; + + (*size)++; + if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) + return false; + + pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1); + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +#endif +} + 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; @@ -517,6 +652,9 @@ static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_t case PB_ATYPE_STATIC: return decode_static_field(stream, wire_type, iter); + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + case PB_ATYPE_CALLBACK: return decode_callback_field(stream, wire_type, iter); @@ -532,7 +670,6 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, { const pb_field_t *field = (const pb_field_t*)extension->type->arg; pb_field_iterator_t iter; - bool dummy; if (field->tag != tag) return true; @@ -543,7 +680,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, iter.required_field_index = 0; iter.dest_struct = extension->dest; iter.pData = extension->dest; - iter.pSize = &dummy; + iter.pSize = &extension->found; return decode_field(stream, wire_type, &iter); } @@ -556,7 +693,7 @@ static bool checkreturn decode_extension(pb_istream_t *stream, pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; size_t pos = stream->bytes_left; - while (extension && pos == stream->bytes_left) + while (extension != NULL && pos == stream->bytes_left) { bool status; if (extension->type->decode) @@ -583,7 +720,7 @@ static bool checkreturn find_extension_field(pb_field_iterator_t *iter) do { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) return true; - pb_field_next(iter); + (void)pb_field_next(iter); } while (iter->field_index != start); return false; @@ -595,45 +732,60 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str pb_field_iterator_t iter; pb_field_init(&iter, fields, dest_struct); - /* Initialize size/has fields and apply default values */ do { pb_type_t type; type = iter.pos->type; + /* Avoid crash on empty message types (zero fields) */ if (iter.pos->tag == 0) continue; if (PB_ATYPE(type) == PB_ATYPE_STATIC) { - /* Initialize the size field for optional/repeated fields to 0. */ if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) { + /* Set has_field to false. Still initialize the optional field + * itself also. */ *(bool*)iter.pSize = false; } else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { + /* Set array count to 0, no need to initialize contents. */ *(size_t*)iter.pSize = 0; - continue; /* Array is empty, no need to initialize contents */ + continue; } - /* Initialize field contents to default value */ if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE) { + /* Initialize submessage to defaults */ pb_message_set_to_defaults((const pb_field_t *) iter.pos->ptr, iter.pData); } else if (iter.pos->ptr != NULL) { + /* Initialize to default value */ memcpy(iter.pData, iter.pos->ptr, iter.pos->data_size); } else { + /* Initialize to zeros */ memset(iter.pData, 0, iter.pos->data_size); } } + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL. */ + *(void**)iter.pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + *(size_t*)iter.pSize = 0; + } + } else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) { - continue; /* Don't overwrite callback */ + /* Don't overwrite callback */ } } while (pb_field_next(&iter)); } @@ -644,7 +796,7 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) { - uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0}; /* Used to check for required fields */ + uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint32_t extension_range_start = 0; pb_field_iterator_t iter; @@ -720,7 +872,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ } while (pb_field_next(&iter)); /* Fixup if last field was also required. */ - if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag) + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) req_field_count++; /* Check the whole bytes */ @@ -740,8 +892,16 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) { + bool status; pb_message_set_to_defaults(fields, dest_struct); - return pb_decode_noinit(stream, fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; } bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) @@ -757,6 +917,62 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * return status; } +#ifdef PB_ENABLE_MALLOC +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iterator_t iter; + pb_field_init(&iter, fields, dest_struct); + + do + { + pb_type_t type; + type = iter.pos->type; + + /* Avoid crash on empty message types (zero fields) */ + if (iter.pos->tag == 0) + continue; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter.pData; + size_t count = *(size_t*)iter.pSize; + while (count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessages */ + void *pItem = *(void**)iter.pData; + size_t count = (pItem ? 1 : 0); + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + count = *(size_t*)iter.pSize; + } + + while (count--) + { + pb_release((const pb_field_t*)iter.pos->ptr, pItem); + pItem = (uint8_t*)pItem + iter.pos->data_size; + } + } + + /* Release main item */ + pb_free(*(void**)iter.pData); + *(void**)iter.pData = NULL; + } + } while (pb_field_next(&iter)); +} +#endif + /* Field decoders */ bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) @@ -815,7 +1031,25 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest) #endif } -bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + switch (field->data_size) + { + case 1: *(int8_t*)dest = (int8_t)value; break; + case 2: *(int16_t*)dest = (int16_t)value; break; + case 4: *(int32_t*)dest = (int32_t)value; break; + case 8: *(int64_t*)dest = (int64_t)value; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return true; +} + +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) { uint64_t value; if (!pb_decode_varint(stream, &value)) @@ -823,8 +1057,6 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo switch (field->data_size) { - 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"); @@ -833,7 +1065,7 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo return true; } -bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) { int64_t value; if (!pb_decode_svarint(stream, &value)) @@ -849,51 +1081,80 @@ bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, v return true; } -bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) { UNUSED(field); return pb_decode_fixed32(stream, dest); } -bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) { UNUSED(field); return pb_decode_fixed64(stream, dest); } -bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) { - pb_bytes_array_t *x = (pb_bytes_array_t*)dest; + uint32_t size; + pb_bytes_array_t *bdest; - uint32_t temp; - if (!pb_decode_varint32(stream, &temp)) + if (!pb_decode_varint32(stream, &size)) return false; - x->size = temp; - /* Check length, noting the space taken by the size_t header. */ - if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) - PB_RETURN_ERROR(stream, "bytes overflow"); + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, PB_BYTES_ARRAY_T_ALLOCSIZE(size), 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (PB_BYTES_ARRAY_T_ALLOCSIZE(size) > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } - return pb_read(stream, x->bytes, x->size); + bdest->size = size; + return pb_read(stream, bdest->bytes, size); } -bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) { uint32_t size; + size_t alloc_size; bool status; if (!pb_decode_varint32(stream, &size)) return false; - /* Check length, noting the null terminator */ - if (size + 1 > field->data_size) - PB_RETURN_ERROR(stream, "string overflow"); + /* Space for null terminator */ + alloc_size = size + 1; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } status = pb_read(stream, (uint8_t*)dest, size); *((uint8_t*)dest + size) = 0; return status; } -bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) { bool status; pb_istream_t substream;