X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=pb_decode.c;h=5cdcbcfb10c97d20204f63318aea8af4e11c2f4f;hb=6b63b26404064272394740f6b7354e75c5805cec;hp=5982c8e5af7ced4a923eddf115651bef45e9278d;hpb=a0f0440394ac3b38105dfad09366f95011c5d8d3;p=apps%2Fagl-service-can-low-level.git diff --git a/pb_decode.c b/pb_decode.c index 5982c8e5..5cdcbcfb 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -48,6 +48,7 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream); #ifdef PB_ENABLE_MALLOC static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); static void pb_release_single_field(const pb_field_iter_t *iter); #endif @@ -393,6 +394,17 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t return func(stream, iter->pos, pItem); } + case PB_HTYPE_ONEOF: + *(pb_size_t*)iter->pSize = iter->pos->tag; + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); + } + return func(stream, iter->pos, iter->pData); + default: PB_RETURN_ERROR(stream, "invalid field type"); } @@ -470,6 +482,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { case PB_HTYPE_REQUIRED: case PB_HTYPE_OPTIONAL: + case PB_HTYPE_ONEOF: if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && *(void**)iter->pData != NULL) { @@ -477,6 +490,11 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ pb_release_single_field(iter); } + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = iter->pos->tag; + } + if (PB_LTYPE(type) == PB_LTYPE_STRING || PB_LTYPE(type) == PB_LTYPE_BYTES) { @@ -562,7 +580,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ initialize_pointer_field(pItem, iter); return func(stream, iter->pos, pItem); } - + default: PB_RETURN_ERROR(stream, "invalid field type"); } @@ -618,6 +636,16 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) { +#ifdef PB_ENABLE_MALLOC + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) + { + if (!pb_release_union_field(stream, iter)) + return false; + } +#endif + switch (PB_ATYPE(iter->pos->type)) { case PB_ATYPE_STATIC: @@ -737,13 +765,15 @@ static void pb_field_set_to_default(pb_field_iter_t *iter) * itself also. */ *(bool*)iter->pSize = false; } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) { - /* Set array count to 0, no need to initialize contents. */ + /* REPEATED: Set array count to 0, no need to initialize contents. + ONEOF: Set which_field to 0. */ *(pb_size_t*)iter->pSize = 0; init_data = false; } - + if (init_data) { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) @@ -769,7 +799,8 @@ static void pb_field_set_to_default(pb_field_iter_t *iter) *(void**)iter->pData = NULL; /* Initialize array count to 0. */ - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) { *(pb_size_t*)iter->pSize = 0; } @@ -855,7 +886,8 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) { - fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); + uint8_t tmp = (uint8_t)(1 << (iter.required_field_index & 7)); + fields_seen[iter.required_field_index >> 3] |= tmp; } if (!decode_field(stream, wire_type, &iter)) @@ -923,11 +955,45 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * } #ifdef PB_ENABLE_MALLOC +/* Given an oneof field, if there has already been a field inside this oneof, + * release it before overwriting with a different one. */ +static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) +{ + pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ + + if (old_tag == 0) + return true; /* Ok, no old data in union */ + + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ + + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); + + pb_release_single_field(iter); + + /* Restore iterator to where it should be. + * This shouldn't fail unless the pb_field_t structure is corrupted. */ + if (!pb_field_iter_find(iter, new_tag)) + PB_RETURN_ERROR(stream, "iterator error"); + + return true; +} + static void pb_release_single_field(const pb_field_iter_t *iter) { pb_type_t type; type = iter->pos->type; + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + if (*(pb_size_t*)iter->pSize != iter->pos->tag) + return; /* This is not the current field in the union */ + } + /* Release anything contained inside an extension or submsg. * This has to be done even if the submsg itself is statically * allocated. */