From c361c1fab7d3de4118d611cc8b163d422608d17d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 11 Dec 2020 08:31:41 +0800 Subject: [PATCH] Update to nanopb 0.4.4 --- .gitignore | 2 +- bin/regen-protos.sh | 7 +- lib/nanopb/include/pb.h | 363 ++++++++++++++++++--------------- lib/nanopb/include/pb_common.h | 4 + lib/nanopb/include/pb_decode.h | 8 +- lib/nanopb/include/pb_encode.h | 2 +- lib/nanopb/src/pb_common.c | 200 +++++++++++------- lib/nanopb/src/pb_decode.c | 357 ++++++++++++++------------------ lib/nanopb/src/pb_encode.c | 73 +++++-- 9 files changed, 556 insertions(+), 460 deletions(-) diff --git a/.gitignore b/.gitignore index 0ec49e6f6..5ab921d31 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,5 @@ Thumbs.db .cproject .idea/* .vagrant - +nanopb* flash.uf2 diff --git a/bin/regen-protos.sh b/bin/regen-protos.sh index 817dc5d24..ce82d3c36 100755 --- a/bin/regen-protos.sh +++ b/bin/regen-protos.sh @@ -2,10 +2,13 @@ set -e -echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.1" +echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.4 to be located in the" +echo "meshtastic-device root directory if the following step fails, you should download the correct" +echo "prebuilt binaries for your computer into nanopb-0.4.4" + # the nanopb tool seems to require that the .options file be in the current directory! cd proto -../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto *.proto +../nanopb-0.4.4/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto *.proto echo "Regenerating protobuf documentation - if you see an error message" echo "you can ignore it unless doing a new protobuf release to github." diff --git a/lib/nanopb/include/pb.h b/lib/nanopb/include/pb.h index 45504e992..ae687ebc9 100644 --- a/lib/nanopb/include/pb.h +++ b/lib/nanopb/include/pb.h @@ -11,7 +11,7 @@ *****************************************************************/ /* Enable support for dynamically allocated fields */ -#define PB_ENABLE_MALLOC 1 +/* #define PB_ENABLE_MALLOC 1 */ /* Define this if your CPU / compiler combination does not support * unaligned memory access to packed structures. */ @@ -55,7 +55,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.4.1 +#define NANOPB_VERSION nanopb-0.4.4 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: @@ -276,17 +276,18 @@ typedef struct pb_field_iter_s pb_field_iter_t; /* This structure is used in auto-generated constants * to specify struct fields. */ -PB_PACKED_STRUCT_START typedef struct pb_msgdesc_s pb_msgdesc_t; struct pb_msgdesc_s { - pb_size_t field_count; const uint32_t *field_info; const pb_msgdesc_t * const * submsg_info; const pb_byte_t *default_value; bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field); -} pb_packed; -PB_PACKED_STRUCT_END + + pb_size_t field_count; + pb_size_t required_field_count; + pb_size_t largest_tag; +}; /* Iterator for message descriptor */ struct pb_field_iter_s { @@ -469,137 +470,181 @@ struct pb_extension_s { }; \ const pb_msgdesc_t structname ## _msg = \ { \ - 0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \ structname ## _field_info, \ structname ## _submsg_info, \ msgname ## _DEFAULT, \ msgname ## _CALLBACK, \ + 0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \ + 0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \ + 0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \ }; \ msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname) #define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1 +#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \ + + (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED) +#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \ + * 0 + tag +/* X-macro for generating the entries in struct_field_info[] array. */ #define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(1, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(2, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(4, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(8, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \ + tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) -#define PB_GEN_FIELD_INFO_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag) +#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) -#define PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname)) +#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size) +/* X-macro for generating asserts that entries fit in struct_field_info[] array. + * The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(), + * but it is not easily reused because of how macro substitutions work. */ #define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(1, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(2, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(4, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(8, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \ + tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) -#define PB_GEN_FIELD_INFO_ASSERT_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag) +#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) -#define PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname)) +#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size) -#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname) -#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname) -#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname) -#define PB_DATA_OFFSET_REQUIRED(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_SINGULAR(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DATA_OFFSET_OPTIONAL(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_REPEATED(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_FIXARRAY(structname, fieldname) offsetof(structname, fieldname) +#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) +#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) +#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) +#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname)) +#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname) -#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SIZE_OFFSET_ ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SIZE_OFFSET_PTR_ ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SIZE_OFFSET_CB_ ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_REQUIRED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_SINGULAR(structname, fieldname) 0 -#define PB_SIZE_OFFSET_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname)) -#define PB_SIZE_OFFSET_ONEOF2(structname, fullname, unionname) PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname) -#define PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname) -#define PB_SIZE_OFFSET_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname) -#define PB_SIZE_OFFSET_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count) -#define PB_SIZE_OFFSET_FIXARRAY(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_REQUIRED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_SINGULAR(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname) -#define PB_SIZE_OFFSET_PTR_OPTIONAL(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_REPEATED(structname, fieldname) PB_SIZE_OFFSET_REPEATED(structname, fieldname) -#define PB_SIZE_OFFSET_PTR_FIXARRAY(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_REQUIRED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_SINGULAR(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname) -#define PB_SIZE_OFFSET_CB_OPTIONAL(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_REPEATED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_FIXARRAY(structname, fieldname) 0 +#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname) +#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname) +#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname) +#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0 +#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0 +#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname)) +#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) +#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname) +#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname) +#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count) +#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname) +#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname) +#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname) +#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0 -#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_ARRAY_SIZE_ ## htype(structname, fieldname) -#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_ARRAY_SIZE_PTR_ ## htype(structname, fieldname) +#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname) +#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname) #define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1 -#define PB_ARRAY_SIZE_REQUIRED(structname, fieldname) 1 -#define PB_ARRAY_SIZE_SINGULAR(structname, fieldname) 1 -#define PB_ARRAY_SIZE_OPTIONAL(structname, fieldname) 1 -#define PB_ARRAY_SIZE_ONEOF(structname, fieldname) 1 -#define PB_ARRAY_SIZE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname) -#define PB_ARRAY_SIZE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname) -#define PB_ARRAY_SIZE_PTR_REQUIRED(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_SINGULAR(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_OPTIONAL(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_ONEOF(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_REPEATED(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0]) +#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname) +#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname) +#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0]) -#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DATA_SIZE_ ## htype(structname, fieldname) -#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DATA_SIZE_PTR_ ## htype(structname, fieldname) -#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DATA_SIZE_CB_ ## htype(structname, fieldname) -#define PB_DATA_SIZE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DATA_SIZE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0]) -#define PB_DATA_SIZE_PTR_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0]) -#define PB_DATA_SIZE_CB_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DATA_SIZE_CB_REPEATED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname) +#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname) +#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname) +#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) +#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0]) +#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0]) +#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) +#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname) #define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple) #define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname @@ -607,37 +652,37 @@ struct pb_extension_s { #define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname #define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \ - PB_SUBMSG_INFO_ ## htype(ltype, structname, fieldname) + PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname) -#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) #define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname)) #define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) -#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE) -#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_BOOL(t) -#define PB_SUBMSG_INFO_BYTES(t) -#define PB_SUBMSG_INFO_DOUBLE(t) -#define PB_SUBMSG_INFO_ENUM(t) -#define PB_SUBMSG_INFO_UENUM(t) -#define PB_SUBMSG_INFO_FIXED32(t) -#define PB_SUBMSG_INFO_FIXED64(t) -#define PB_SUBMSG_INFO_FLOAT(t) -#define PB_SUBMSG_INFO_INT32(t) -#define PB_SUBMSG_INFO_INT64(t) -#define PB_SUBMSG_INFO_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t) -#define PB_SUBMSG_INFO_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t) -#define PB_SUBMSG_INFO_SFIXED32(t) -#define PB_SUBMSG_INFO_SFIXED64(t) -#define PB_SUBMSG_INFO_SINT32(t) -#define PB_SUBMSG_INFO_SINT64(t) -#define PB_SUBMSG_INFO_STRING(t) -#define PB_SUBMSG_INFO_UINT32(t) -#define PB_SUBMSG_INFO_UINT64(t) -#define PB_SUBMSG_INFO_EXTENSION(t) -#define PB_SUBMSG_INFO_FIXED_LENGTH_BYTES(t) +#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE) +#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SI_PB_LTYPE_BOOL(t) +#define PB_SI_PB_LTYPE_BYTES(t) +#define PB_SI_PB_LTYPE_DOUBLE(t) +#define PB_SI_PB_LTYPE_ENUM(t) +#define PB_SI_PB_LTYPE_UENUM(t) +#define PB_SI_PB_LTYPE_FIXED32(t) +#define PB_SI_PB_LTYPE_FIXED64(t) +#define PB_SI_PB_LTYPE_FLOAT(t) +#define PB_SI_PB_LTYPE_INT32(t) +#define PB_SI_PB_LTYPE_INT64(t) +#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t) +#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t) +#define PB_SI_PB_LTYPE_SFIXED32(t) +#define PB_SI_PB_LTYPE_SFIXED64(t) +#define PB_SI_PB_LTYPE_SINT32(t) +#define PB_SI_PB_LTYPE_SINT64(t) +#define PB_SI_PB_LTYPE_STRING(t) +#define PB_SI_PB_LTYPE_UINT32(t) +#define PB_SI_PB_LTYPE_UINT64(t) +#define PB_SI_PB_LTYPE_EXTENSION(t) +#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t) #define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg), /* The field descriptors use a variable width format, with width of either @@ -726,37 +771,37 @@ struct pb_extension_s { * The generator will give explicit size argument when it knows that a message * structure grows beyond 1-word format limits. */ -#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FIELDINFO_WIDTH_ ## atype(htype, ltype) -#define PB_FIELDINFO_WIDTH_STATIC(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype) -#define PB_FIELDINFO_WIDTH_POINTER(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype) -#define PB_FIELDINFO_WIDTH_CALLBACK(htype, ltype) 2 -#define PB_FIELDINFO_WIDTH_REQUIRED(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_SINGULAR(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_OPTIONAL(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_ONEOF(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_REPEATED(ltype) 2 -#define PB_FIELDINFO_WIDTH_FIXARRAY(ltype) 2 -#define PB_FIELDINFO_WIDTH_BOOL 1 -#define PB_FIELDINFO_WIDTH_BYTES 2 -#define PB_FIELDINFO_WIDTH_DOUBLE 1 -#define PB_FIELDINFO_WIDTH_ENUM 1 -#define PB_FIELDINFO_WIDTH_UENUM 1 -#define PB_FIELDINFO_WIDTH_FIXED32 1 -#define PB_FIELDINFO_WIDTH_FIXED64 1 -#define PB_FIELDINFO_WIDTH_FLOAT 1 -#define PB_FIELDINFO_WIDTH_INT32 1 -#define PB_FIELDINFO_WIDTH_INT64 1 -#define PB_FIELDINFO_WIDTH_MESSAGE 2 -#define PB_FIELDINFO_WIDTH_MSG_W_CB 2 -#define PB_FIELDINFO_WIDTH_SFIXED32 1 -#define PB_FIELDINFO_WIDTH_SFIXED64 1 -#define PB_FIELDINFO_WIDTH_SINT32 1 -#define PB_FIELDINFO_WIDTH_SINT64 1 -#define PB_FIELDINFO_WIDTH_STRING 2 -#define PB_FIELDINFO_WIDTH_UINT32 1 -#define PB_FIELDINFO_WIDTH_UINT64 1 -#define PB_FIELDINFO_WIDTH_EXTENSION 1 -#define PB_FIELDINFO_WIDTH_FIXED_LENGTH_BYTES 2 +#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype) +#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype) +#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype) +#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2 +#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2 +#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2 +#define PB_FI_WIDTH_PB_LTYPE_BOOL 1 +#define PB_FI_WIDTH_PB_LTYPE_BYTES 2 +#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1 +#define PB_FI_WIDTH_PB_LTYPE_ENUM 1 +#define PB_FI_WIDTH_PB_LTYPE_UENUM 1 +#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1 +#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1 +#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1 +#define PB_FI_WIDTH_PB_LTYPE_INT32 1 +#define PB_FI_WIDTH_PB_LTYPE_INT64 1 +#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2 +#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2 +#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1 +#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1 +#define PB_FI_WIDTH_PB_LTYPE_SINT32 1 +#define PB_FI_WIDTH_PB_LTYPE_SINT64 1 +#define PB_FI_WIDTH_PB_LTYPE_STRING 2 +#define PB_FI_WIDTH_PB_LTYPE_UINT32 1 +#define PB_FI_WIDTH_PB_LTYPE_UINT64 1 +#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1 +#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2 /* The mapping from protobuf types to LTYPEs is done using these macros. */ #define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL diff --git a/lib/nanopb/include/pb_common.h b/lib/nanopb/include/pb_common.h index 47fa2c99e..58aa90f76 100644 --- a/lib/nanopb/include/pb_common.h +++ b/lib/nanopb/include/pb_common.h @@ -32,6 +32,10 @@ bool pb_field_iter_next(pb_field_iter_t *iter); * Returns false if no such field exists. */ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); +/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found. + * There can be only one extension range field per message. */ +bool pb_field_iter_find_extension(pb_field_iter_t *iter); + #ifdef PB_VALIDATE_UTF8 /* Validate UTF-8 text string */ bool pb_validate_utf8(const char *s); diff --git a/lib/nanopb/include/pb_decode.h b/lib/nanopb/include/pb_decode.h index b64d95aea..824acd4ea 100644 --- a/lib/nanopb/include/pb_decode.h +++ b/lib/nanopb/include/pb_decode.h @@ -113,6 +113,9 @@ bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_s * pb_decode() returns with an error, the message is already released. */ void pb_release(const pb_msgdesc_t *fields, void *dest_struct); +#else +/* Allocation is not supported, so release is no-op */ +#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct); #endif @@ -121,11 +124,14 @@ void pb_release(const pb_msgdesc_t *fields, void *dest_struct); **************************************/ /* Create an input stream for reading from a memory buffer. + * + * msglen should be the actual length of the message, not the full size of + * allocated buffer. * * Alternatively, you can use a custom stream that reads directly from e.g. * a file or a network socket. */ -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen); /* Function to read from a pb_istream_t. You can use this if you need to * read some custom header data, or to read data in field callbacks. diff --git a/lib/nanopb/include/pb_encode.h b/lib/nanopb/include/pb_encode.h index 88e246a2d..9cff22a4f 100644 --- a/lib/nanopb/include/pb_encode.h +++ b/lib/nanopb/include/pb_encode.h @@ -132,7 +132,7 @@ bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); * structure. Call this from the callback before writing out field contents. */ bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field); -/* Encode field header by manually specifing wire type. You need to use this +/* Encode field header by manually specifying wire type. You need to use this * if you want to write out packed arrays from a callback field. */ bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); diff --git a/lib/nanopb/src/pb_common.c b/lib/nanopb/src/pb_common.c index dfc5a05b0..6aee76b1e 100644 --- a/lib/nanopb/src/pb_common.c +++ b/lib/nanopb/src/pb_common.c @@ -9,89 +9,102 @@ static bool load_descriptor_values(pb_field_iter_t *iter) { uint32_t word0; uint32_t data_offset; - uint_least8_t format; int_least8_t size_offset; if (iter->index >= iter->descriptor->field_count) return false; word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); - format = word0 & 3; - iter->tag = (pb_size_t)((word0 >> 2) & 0x3F); iter->type = (pb_type_t)((word0 >> 8) & 0xFF); - if (format == 0) + switch(word0 & 3) { - /* 1-word format */ - iter->array_size = 1; - size_offset = (int_least8_t)((word0 >> 24) & 0x0F); - data_offset = (word0 >> 16) & 0xFF; - iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F); - } - else if (format == 1) - { - /* 2-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); + case 0: { + /* 1-word format */ + iter->array_size = 1; + iter->tag = (pb_size_t)((word0 >> 2) & 0x3F); + size_offset = (int_least8_t)((word0 >> 24) & 0x0F); + data_offset = (word0 >> 16) & 0xFF; + iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F); + break; + } - iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF); - iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6)); - size_offset = (int_least8_t)((word0 >> 28) & 0x0F); - data_offset = word1 & 0xFFFF; - iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF); - } - else if (format == 2) - { - /* 4-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); - uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); + case 1: { + /* 2-word format */ + uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - iter->array_size = (pb_size_t)(word0 >> 16); - iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6)); - size_offset = (int_least8_t)(word1 & 0xFF); - data_offset = word2; - iter->data_size = (pb_size_t)word3; - } - else - { - /* 8-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); - uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); - uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]); + iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF); + iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6)); + size_offset = (int_least8_t)((word0 >> 28) & 0x0F); + data_offset = word1 & 0xFFFF; + iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF); + break; + } - iter->array_size = (pb_size_t)word4; - iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6)); - size_offset = (int_least8_t)(word1 & 0xFF); - data_offset = word2; - iter->data_size = (pb_size_t)word3; + case 2: { + /* 4-word format */ + uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); + uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); + uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); + + iter->array_size = (pb_size_t)(word0 >> 16); + iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6)); + size_offset = (int_least8_t)(word1 & 0xFF); + data_offset = word2; + iter->data_size = (pb_size_t)word3; + break; + } + + default: { + /* 8-word format */ + uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); + uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); + uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); + uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]); + + iter->array_size = (pb_size_t)word4; + iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6)); + size_offset = (int_least8_t)(word1 & 0xFF); + data_offset = word2; + iter->data_size = (pb_size_t)word3; + break; + } } - iter->pField = (char*)iter->message + data_offset; - - if (size_offset) - { - iter->pSize = (char*)iter->pField - size_offset; - } - else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && - (PB_ATYPE(iter->type) == PB_ATYPE_STATIC || - PB_ATYPE(iter->type) == PB_ATYPE_POINTER)) - { - /* Fixed count array */ - iter->pSize = &iter->array_size; - } - else + if (!iter->message) { + /* Avoid doing arithmetic on null pointers, it is undefined */ + iter->pField = NULL; iter->pSize = NULL; } - - if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL) - { - iter->pData = *(void**)iter->pField; - } else { - iter->pData = iter->pField; + iter->pField = (char*)iter->message + data_offset; + + if (size_offset) + { + iter->pSize = (char*)iter->pField - size_offset; + } + else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && + (PB_ATYPE(iter->type) == PB_ATYPE_STATIC || + PB_ATYPE(iter->type) == PB_ATYPE_POINTER)) + { + /* Fixed count array */ + iter->pSize = &iter->array_size; + } + else + { + iter->pSize = NULL; + } + + if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL) + { + iter->pData = *(void**)iter->pField; + } + else + { + iter->pData = iter->pField; + } } if (PB_LTYPE_IS_SUBMSG(iter->type)) @@ -130,17 +143,13 @@ static void advance_iterator(pb_field_iter_t *iter) pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF; pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3)); + /* Add to fields. + * The cast to pb_size_t is needed to avoid -Wconversion warning. + * Because the data is is constants from generator, there is no danger of overflow. + */ iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len); - - if (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED) - { - iter->required_field_index++; - } - - if (PB_LTYPE_IS_SUBMSG(prev_type)) - { - iter->submessage_index++; - } + iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED)); + iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type)); } } @@ -189,11 +198,23 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) { return true; /* Nothing to do, correct field already. */ } + else if (tag > iter->descriptor->largest_tag) + { + return false; + } else { pb_size_t start = iter->index; uint32_t fieldinfo; + if (tag < iter->tag) + { + /* Fields are in tag number order, so we know that tag is between + * 0 and our start position. Setting index to end forces + * advance_iterator() call below to restart from beginning. */ + iter->index = iter->descriptor->field_count; + } + do { /* Advance iterator but don't load values yet */ @@ -222,6 +243,37 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) } } +bool pb_field_iter_find_extension(pb_field_iter_t *iter) +{ + if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION) + { + return true; + } + else + { + pb_size_t start = iter->index; + uint32_t fieldinfo; + + do + { + /* Advance iterator but don't load values yet */ + advance_iterator(iter); + + /* Do fast check for field type */ + fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); + + if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION) + { + return load_descriptor_values(iter); + } + } while (iter->index != start); + + /* Searched all the way back to start, and found nothing. */ + (void)load_descriptor_values(iter); + return false; + } +} + static void *pb_const_cast(const void *p) { /* Note: this casts away const, in order to use the common field iterator diff --git a/lib/nanopb/src/pb_decode.c b/lib/nanopb/src/pb_decode.c index f936412b7..28f6b5799 100644 --- a/lib/nanopb/src/pb_decode.c +++ b/lib/nanopb/src/pb_decode.c @@ -24,19 +24,17 @@ static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); -static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field); +static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension); +static bool pb_field_set_to_default(pb_field_iter_t *field); static bool pb_message_set_to_defaults(pb_field_iter_t *iter); static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field); @@ -59,6 +57,8 @@ static void pb_release_single_field(pb_field_iter_t *field); #define pb_uint64_t uint64_t #endif +#define PB_WT_PACKED ((pb_wire_type_t)0xFF) + typedef struct { uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32]; } pb_fields_seen_t; @@ -139,7 +139,7 @@ static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) return true; } -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen) { pb_istream_t stream; /* Cast away the const from buf without a compiler error. We are @@ -156,7 +156,7 @@ pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) #endif state.c_state = buf; stream.state = state.state; - stream.bytes_left = bufsize; + stream.bytes_left = msglen; #ifndef PB_NO_ERRMSG stream.errmsg = NULL; #endif @@ -205,8 +205,10 @@ static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *d { /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; - - if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) + bool valid_extension = ((byte & 0x7F) == 0x00 || + ((result >> 31) != 0 && byte == sign_extension)); + + if (bitpos >= 64 || !valid_extension) { PB_RETURN_ERROR(stream, "varint overflow"); } @@ -388,61 +390,70 @@ bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *s * Decode a single field * *************************/ -static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field) +static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) { switch (PB_LTYPE(field->type)) { case PB_LTYPE_BOOL: - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - return wire_type == PB_WT_VARINT; + if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); - case PB_LTYPE_FIXED32: - return wire_type == PB_WT_32BIT; - - case PB_LTYPE_FIXED64: - return wire_type == PB_WT_64BIT; - - case PB_LTYPE_BYTES: - case PB_LTYPE_STRING: - case PB_LTYPE_SUBMESSAGE: - case PB_LTYPE_SUBMSG_W_CB: - case PB_LTYPE_FIXED_LENGTH_BYTES: - return wire_type == PB_WT_STRING; - - default: - return false; - } -} - -static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field) -{ - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_BOOL: return pb_dec_bool(stream, field); case PB_LTYPE_VARINT: case PB_LTYPE_UVARINT: case PB_LTYPE_SVARINT: + if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_varint(stream, field); case PB_LTYPE_FIXED32: + if (wire_type != PB_WT_32BIT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); + + return pb_decode_fixed32(stream, field->pData); + case PB_LTYPE_FIXED64: - return pb_dec_fixed(stream, field); + if (wire_type != PB_WT_64BIT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); + +#ifdef PB_CONVERT_DOUBLE_FLOAT + if (field->data_size == sizeof(float)) + { + return pb_decode_double_as_float(stream, (float*)field->pData); + } +#endif + +#ifdef PB_WITHOUT_64BIT + PB_RETURN_ERROR(stream, "invalid data_size"); +#else + return pb_decode_fixed64(stream, field->pData); +#endif case PB_LTYPE_BYTES: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_bytes(stream, field); case PB_LTYPE_STRING: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_string(stream, field); case PB_LTYPE_SUBMESSAGE: case PB_LTYPE_SUBMSG_W_CB: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_submessage(stream, field); case PB_LTYPE_FIXED_LENGTH_BYTES: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_fixed_length_bytes(stream, field); default: @@ -455,18 +466,12 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t switch (PB_HTYPE(field->type)) { case PB_HTYPE_REQUIRED: - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); case PB_HTYPE_OPTIONAL: - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if (field->pSize != NULL) *(bool*)field->pSize = true; - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); case PB_HTYPE_REPEATED: if (wire_type == PB_WT_STRING @@ -483,7 +488,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t while (substream.bytes_left > 0 && *size < field->array_size) { - if (!decode_basic_field(&substream, field)) + if (!decode_basic_field(&substream, PB_WT_PACKED, field)) { status = false; break; @@ -505,18 +510,15 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t pb_size_t *size = (pb_size_t*)field->pSize; field->pData = (char*)field->pField + field->data_size * (*size); - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if ((*size)++ >= field->array_size) PB_RETURN_ERROR(stream, "array overflow"); - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } case PB_HTYPE_ONEOF: - *(pb_size_t*)field->pSize = field->tag; - if (PB_LTYPE_IS_SUBMSG(field->type)) + if (PB_LTYPE_IS_SUBMSG(field->type) && + *(pb_size_t*)field->pSize != field->tag) { /* We memset to zero so that any callbacks are set to NULL. * This is because the callbacks might otherwise have values @@ -526,12 +528,14 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t * that can set the fields before submessage is decoded. * pb_dec_submessage() will set any default values. */ memset(field->pData, 0, (size_t)field->data_size); + + /* Set default values for the submessage fields. */ + if (!pb_field_set_to_default(field)) + PB_RETURN_ERROR(stream, "failed to set defaults"); } + *(pb_size_t*)field->pSize = field->tag; - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); default: PB_RETURN_ERROR(stream, "invalid field type"); @@ -599,14 +603,8 @@ static void initialize_pointer_field(void *pItem, pb_field_iter_t *field) else if (PB_LTYPE_IS_SUBMSG(field->type)) { /* We memset to zero so that any callbacks are set to NULL. - * Then set any default values. */ - pb_field_iter_t submsg_iter; + * Default values will be set by pb_dec_submessage(). */ memset(pItem, 0, field->data_size); - - if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, pItem)) - { - (void)pb_message_set_to_defaults(&submsg_iter); - } } } #endif @@ -623,9 +621,6 @@ 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 (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL) { /* Duplicate field, have to release the old allocation first. */ @@ -643,7 +638,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { /* pb_dec_string and pb_dec_bytes handle allocation themselves */ field->pData = field->pField; - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } else { @@ -652,7 +647,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ field->pData = *(void**)field->pField; initialize_pointer_field(field->pData, field); - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } case PB_HTYPE_REPEATED: @@ -700,7 +695,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ /* Decode the array entry */ field->pData = *(char**)field->pField + field->data_size * (*size); initialize_pointer_field(field->pData, field); - if (!decode_basic_field(&substream, field)) + if (!decode_basic_field(&substream, PB_WT_PACKED, field)) { status = false; break; @@ -721,16 +716,13 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ if (*size == PB_SIZE_MAX) PB_RETURN_ERROR(stream, "too many array entries"); - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1))) return false; field->pData = *(char**)field->pField + field->data_size * (*size); (*size)++; initialize_pointer_field(field->pData, field); - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } default: @@ -821,7 +813,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, if (!pb_field_iter_begin_extension(&iter, extension)) PB_RETURN_ERROR(stream, "invalid extension"); - if (iter.tag != tag) + if (iter.tag != tag || !iter.message) return true; extension->found = true; @@ -831,9 +823,8 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, /* Try to decode an unknown field as an extension field. Tries each extension * decoder in turn, until one of them handles the field or loop ends. */ static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) + uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension) { - pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; size_t pos = stream->bytes_left; while (extension != NULL && pos == stream->bytes_left) @@ -853,22 +844,6 @@ static bool checkreturn decode_extension(pb_istream_t *stream, return true; } -/* Step through the iterator until an extension field is found or until all - * entries have been checked. There can be only one extension field per - * message. Returns false if no extension field is found. */ -static bool checkreturn find_extension_field(pb_field_iter_t *iter) -{ - pb_size_t start = iter->index; - - do { - if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION) - return true; - (void)pb_field_iter_next(iter); - } while (iter->index != start); - - return false; -} - /* Initialize message fields to default values, recursively */ static bool pb_field_set_to_default(pb_field_iter_t *field) { @@ -910,9 +885,14 @@ static bool pb_field_set_to_default(pb_field_iter_t *field) if (init_data) { - if (PB_LTYPE_IS_SUBMSG(field->type)) + if (PB_LTYPE_IS_SUBMSG(field->type) && + (field->submsg_desc->default_value != NULL || + field->submsg_desc->field_callback != NULL || + field->submsg_desc->submsg_info[0] != NULL)) { - /* Initialize submessage to defaults */ + /* Initialize submessage to defaults. + * Only needed if it has default values + * or callback/submessage fields. */ pb_field_iter_t submsg_iter; if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData)) { @@ -989,6 +969,7 @@ static bool pb_message_set_to_defaults(pb_field_iter_t *iter) static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags) { uint32_t extension_range_start = 0; + pb_extension_t *extensions = NULL; /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed * count field. This can only handle _one_ repeated fixed count field that @@ -1040,25 +1021,31 @@ static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION) { /* No match found, check if it matches an extension. */ + if (extension_range_start == 0) + { + if (pb_field_iter_find_extension(&iter)) + { + extensions = *(pb_extension_t* const *)iter.pData; + extension_range_start = iter.tag; + } + + if (!extensions) + { + extension_range_start = (uint32_t)-1; + } + } + if (tag >= extension_range_start) { - if (!find_extension_field(&iter)) - extension_range_start = (uint32_t)-1; - else - extension_range_start = iter.tag; + size_t pos = stream->bytes_left; - if (tag >= extension_range_start) + if (!decode_extension(stream, tag, wire_type, extensions)) + return false; + + if (pos != stream->bytes_left) { - size_t pos = stream->bytes_left; - - if (!decode_extension(stream, tag, wire_type, &iter)) - return false; - - if (pos != stream->bytes_left) - { - /* The field was handled */ - continue; - } + /* The field was handled */ + continue; } } @@ -1112,27 +1099,15 @@ static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t /* Check that all required fields were present. */ { - /* 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. - */ - pb_size_t req_field_count; - pb_type_t last_type; - pb_size_t i; - do { - req_field_count = iter.required_field_index; - last_type = iter.type; - } while (pb_field_iter_next(&iter)); - - /* Fixup if last field was also required. */ - if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.tag != 0) - req_field_count++; - - if (req_field_count > PB_MAX_REQUIRED_FIELDS) - req_field_count = PB_MAX_REQUIRED_FIELDS; + pb_size_t req_field_count = iter.descriptor->required_field_count; if (req_field_count > 0) { + pb_size_t i; + + if (req_field_count > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + /* Check the whole words */ for (i = 0; i < (req_field_count >> 5); i++) { @@ -1277,7 +1252,7 @@ static void pb_release_single_field(pb_field_iter_t *field) if (field->pData) { - while (count--) + for (; count > 0; count--) { pb_release(field->submsg_desc, field->pData); field->pData = (char*)field->pData + field->data_size; @@ -1294,7 +1269,7 @@ static void pb_release_single_field(pb_field_iter_t *field) /* Release entries in repeated string or bytes array */ void **pItem = *(void***)field->pField; pb_size_t count = *(pb_size_t*)field->pSize; - while (count--) + for (; count > 0; count--) { pb_free(*pItem); *pItem++ = NULL; @@ -1454,7 +1429,7 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_ /* See issue 97: Google's C++ protobuf allows negative varint values to * be cast as int32_t, instead of the int64_t that should be used when - * encoding. Previous nanopb versions had a bug in encoding. In order to + * encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to * not break decoding of such messages, we cast <=32 bit fields to * int32_t first to get the sign correct. */ @@ -1483,31 +1458,6 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_ } } -static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field) -{ -#ifdef PB_CONVERT_DOUBLE_FLOAT - if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - return pb_decode_double_as_float(stream, (float*)field->pData); - } -#endif - - if (field->data_size == sizeof(uint32_t)) - { - return pb_decode_fixed32(stream, field->pData); - } -#ifndef PB_WITHOUT_64BIT - else if (field->data_size == sizeof(uint64_t)) - { - return pb_decode_fixed64(stream, field->pData); - } -#endif - else - { - PB_RETURN_ERROR(stream, "invalid data_size"); - } -} - static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field) { uint32_t size; @@ -1601,6 +1551,7 @@ static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field) { bool status = true; + bool submsg_consumed = false; pb_istream_t substream; if (!pb_make_string_substream(stream, &substream)) @@ -1609,19 +1560,6 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_i if (field->submsg_desc == NULL) PB_RETURN_ERROR(stream, "invalid field descriptor"); - /* 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_REPEATED || - PB_HTYPE(field->type) == PB_HTYPE_ONEOF) - { - pb_field_iter_t submsg_iter; - if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData)) - { - if (!pb_message_set_to_defaults(&submsg_iter)) - PB_RETURN_ERROR(stream, "failed to set defaults"); - } - } - /* Submessages can have a separate message-level callback that is called * before decoding the message. Typically it is used to set callback fields * inside oneofs. */ @@ -1632,13 +1570,28 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_i if (callback->funcs.decode) { status = callback->funcs.decode(&substream, field, &callback->arg); + + if (substream.bytes_left == 0) + { + submsg_consumed = true; + } } } /* Now decode the submessage contents */ - if (status) + if (status && !submsg_consumed) { - status = pb_decode_inner(&substream, field->submsg_desc, field->pData, 0); + unsigned int flags = 0; + + /* Static required/optional fields are already initialized by top-level + * pb_decode(), no need to initialize them again. */ + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_HTYPE(field->type) != PB_HTYPE_REPEATED) + { + flags = PB_DECODE_NOINIT; + } + + status = pb_decode_inner(&substream, field->submsg_desc, field->pData, flags); } if (!pb_close_string_substream(stream, &substream)) @@ -1692,37 +1645,41 @@ bool pb_decode_double_as_float(pb_istream_t *stream, float *dest) { /* Special value */ exponent = 128; - } - else if (exponent > 127) - { - /* Too large, convert to infinity */ - exponent = 128; - mantissa = 0; - } - else if (exponent < -150) - { - /* Too small, convert to zero */ - exponent = -127; - mantissa = 0; - } - else if (exponent < -126) - { - /* Denormalized */ - mantissa |= 0x1000000; - mantissa >>= (-126 - exponent); - exponent = -127; - } - - /* Round off mantissa */ - mantissa = (mantissa + 1) >> 1; - - /* Check if mantissa went over 2.0 */ - if (mantissa & 0x800000) - { - exponent += 1; - mantissa &= 0x7FFFFF; mantissa >>= 1; } + else + { + if (exponent > 127) + { + /* Too large, convert to infinity */ + exponent = 128; + mantissa = 0; + } + else if (exponent < -150) + { + /* Too small, convert to zero */ + exponent = -127; + mantissa = 0; + } + else if (exponent < -126) + { + /* Denormalized */ + mantissa |= 0x1000000; + mantissa >>= (-126 - exponent); + exponent = -127; + } + + /* Round off mantissa */ + mantissa = (mantissa + 1) >> 1; + + /* Check if mantissa went over 2.0 */ + if (mantissa & 0x800000) + { + exponent += 1; + mantissa &= 0x7FFFFF; + mantissa >>= 1; + } + } /* Combine fields */ out.i = mantissa; diff --git a/lib/nanopb/src/pb_encode.c b/lib/nanopb/src/pb_encode.c index 409fec396..de716f7a5 100644 --- a/lib/nanopb/src/pb_encode.c +++ b/lib/nanopb/src/pb_encode.c @@ -82,8 +82,11 @@ bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t cou { if (count > 0 && stream->callback != NULL) { - if (stream->bytes_written + count > stream->max_size) + if (stream->bytes_written + count < stream->bytes_written || + stream->bytes_written + count > stream->max_size) + { PB_RETURN_ERROR(stream, "stream full"); + } #ifdef PB_BUFFER_ONLY if (!buf_write(stream, buf, count)) @@ -262,9 +265,33 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie * submessage fields. */ return safe_read_bool(field->pSize) == false; } + else if (field->descriptor->default_value) + { + /* Proto3 messages do not have default values, but proto2 messages + * can contain optional fields without has_fields (generator option 'proto3'). + * In this case they must always be encoded, to make sure that the + * non-zero default value is overwritten. + */ + return false; + } /* Rest is proto3 singular fields */ - if (PB_LTYPE(type) == PB_LTYPE_BYTES) + if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Simple integer / float fields */ + pb_size_t i; + const char *p = (const char*)field->pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } + else if (PB_LTYPE(type) == PB_LTYPE_BYTES) { const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData; return bytes->size == 0; @@ -302,27 +329,29 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie return true; } } - + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) { - /* Catch-all branch that does byte-per-byte comparison for zero value. - * - * This is for all pointer fields, and for static PB_LTYPE_VARINT, - * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also - * callback fields. These all have integer or pointer value which - * can be compared with 0. - */ - pb_size_t i; - const char *p = (const char*)field->pData; - for (i = 0; i < field->data_size; i++) - { - if (p[i] != 0) - { - return false; - } - } - - return true; + return field->pData == NULL; } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; + return extension == NULL; + } + else if (field->descriptor->field_callback == pb_default_field_callback) + { + pb_callback_t *pCallback = (pb_callback_t*)field->pData; + return pCallback->funcs.encode == NULL; + } + else + { + return field->descriptor->field_callback == NULL; + } + } + + return false; /* Not typically reached, safe default for weird special cases. */ } /* Encode a field with static or pointer allocation, i.e. one whose data @@ -823,7 +852,7 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t } if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) + bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) { PB_RETURN_ERROR(stream, "bytes size exceeded"); }