aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2017-08-20 17:56:30 +0200
committerDimitri Sokolyuk <demon@dim13.org>2017-08-20 17:56:30 +0200
commit27e0e60985937b69cf5396ee018665bbc0e0f6f3 (patch)
treebd58999fe49d49ad7810cd6a43239b38f060498a
parent0cb37a1ceda90b439ffc23083aa8d8802fe9df26 (diff)
Sync nanopb
-rw-r--r--car/pb.h69
-rw-r--r--car/pb_decode.c54
-rw-r--r--car/pb_encode.c101
3 files changed, 148 insertions, 76 deletions
diff --git a/car/pb.h b/car/pb.h
index f68d1d6..c7e6bc6 100644
--- a/car/pb.h
+++ b/car/pb.h
@@ -46,7 +46,7 @@
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
-#define NANOPB_VERSION nanopb-0.3.8-dev
+#define NANOPB_VERSION nanopb-0.3.9-dev
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
@@ -427,19 +427,6 @@ struct pb_extension_s {
pb_membersize(st, m[0]), \
pb_arraysize(st, m), ptr}
-#define PB_REQUIRED_INLINE(tag, st, m, fd, ltype, ptr) \
- {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | PB_LTYPE_FIXED_LENGTH_BYTES, \
- fd, 0, pb_membersize(st, m), 0, ptr}
-
-/* Optional fields add the delta to the has_ variable. */
-#define PB_OPTIONAL_INLINE(tag, st, m, fd, ltype, ptr) \
- {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED_LENGTH_BYTES, \
- fd, \
- pb_delta(st, has_ ## m, m), \
- pb_membersize(st, m), 0, ptr}
-
-/* INLINE does not support REPEATED fields. */
-
/* Allocated fields carry the size of the actual data, not the pointer */
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
@@ -478,9 +465,14 @@ struct pb_extension_s {
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
-/* Optional extensions don't have the has_ field, as that would be redundant. */
+/* Optional extensions don't have the has_ field, as that would be redundant.
+ * Furthermore, the combination of OPTIONAL without has_ field is used
+ * for indicating proto3 style fields. Extensions exist in proto2 mode only,
+ * so they should be encoded according to proto2 rules. To avoid the conflict,
+ * extensions are marked as REQUIRED instead.
+ */
#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \
- {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
+ {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
0, \
0, \
pb_membersize(st, m), 0, ptr}
@@ -488,31 +480,30 @@ struct pb_extension_s {
#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr)
-/* INLINE does not support OPTEXT. */
-
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr)
/* The mapping from protobuf types to LTYPEs is done using these macros. */
-#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT
-#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES
-#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64
-#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT
-#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT
-#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32
-#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64
-#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32
-#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
-#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
-#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
-#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
-#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
-#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
-#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
-#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
-#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
-#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
-#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
+#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES
+#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64
+#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT
+#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32
+#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64
+#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32
+#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
+#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
+#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
+#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
+#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
+#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
+#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
+#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
+#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
+#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
/* This is the actual macro used in field descriptions.
* It takes these arguments:
@@ -521,7 +512,7 @@ struct pb_extension_s {
* FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
* SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
* - Field rules: REQUIRED, OPTIONAL or REPEATED
- * - Allocation: STATIC, INLINE, or CALLBACK
+ * - Allocation: STATIC, CALLBACK or POINTER
* - Placement: FIRST or OTHER, depending on if this is the first field in structure.
* - Message name
* - Field name
@@ -547,8 +538,6 @@ struct pb_extension_s {
fd, pb_delta(st, which_ ## u, u.m), \
pb_membersize(st, u.m[0]), 0, ptr}
-/* INLINE does not support ONEOF. */
-
#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ONEOF_ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
diff --git a/car/pb_decode.c b/car/pb_decode.c
index 92d0175..b4563cf 100644
--- a/car/pb_decode.c
+++ b/car/pb_decode.c
@@ -42,6 +42,7 @@ static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *f
static bool checkreturn pb_dec_bytes(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);
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);
+static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);
static bool checkreturn pb_skip_varint(pb_istream_t *stream);
static bool checkreturn pb_skip_string(pb_istream_t *stream);
@@ -65,7 +66,7 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
&pb_dec_string,
&pb_dec_submessage,
NULL, /* extensions */
- &pb_dec_bytes /* PB_LTYPE_FIXED_LENGTH_BYTES */
+ &pb_dec_fixed_length_bytes
};
/*******************************
@@ -477,6 +478,9 @@ static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter)
}
else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
{
+ /* We memset to zero so that any callbacks are set to NULL.
+ * Then set any default values. */
+ memset(pItem, 0, iter->pos->data_size);
pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem);
}
}
@@ -615,7 +619,7 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type
void **arg = &(pCallback->arg);
#endif
- if (pCallback->funcs.decode == NULL)
+ if (pCallback == NULL || pCallback->funcs.decode == NULL)
return pb_skip_field(stream, wire_type);
if (wire_type == PB_WT_STRING)
@@ -779,7 +783,7 @@ static void pb_field_set_to_default(pb_field_iter_t *iter)
else if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{
bool init_data = true;
- if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL)
+ if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData)
{
/* Set has_field to false. Still initialize the optional field
* itself also. */
@@ -933,6 +937,9 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
req_field_count++;
+ if (req_field_count > PB_MAX_REQUIRED_FIELDS)
+ req_field_count = PB_MAX_REQUIRED_FIELDS;
+
if (req_field_count > 0)
{
/* Check the whole words */
@@ -942,9 +949,15 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
PB_RETURN_ERROR(stream, "missing required field");
}
- /* Check the remaining bits */
- if (fields_seen[req_field_count >> 5] != (allbits >> (32 - (req_field_count & 31))))
- PB_RETURN_ERROR(stream, "missing required field");
+ /* Check the remaining bits (if any) */
+ if ((req_field_count & 31) != 0)
+ {
+ if (fields_seen[req_field_count >> 5] !=
+ (allbits >> (32 - (req_field_count & 31))))
+ {
+ PB_RETURN_ERROR(stream, "missing required field");
+ }
+ }
}
}
@@ -1286,12 +1299,6 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
}
else
{
- if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES) {
- if (size != field->data_size)
- PB_RETURN_ERROR(stream, "incorrect inline bytes size");
- return pb_read(stream, (pb_byte_t*)dest, field->data_size);
- }
-
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "bytes overflow");
bdest = (pb_bytes_array_t*)dest;
@@ -1359,3 +1366,26 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t
return false;
return status;
}
+
+static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
+{
+ uint32_t size;
+
+ if (!pb_decode_varint32(stream, &size))
+ return false;
+
+ if (size > PB_SIZE_MAX)
+ PB_RETURN_ERROR(stream, "bytes overflow");
+
+ if (size == 0)
+ {
+ /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */
+ memset(dest, 0, field->data_size);
+ return true;
+ }
+
+ if (size != field->data_size)
+ PB_RETURN_ERROR(stream, "incorrect fixed length bytes size");
+
+ return pb_read(stream, (pb_byte_t*)dest, field->data_size);
+}
diff --git a/car/pb_encode.c b/car/pb_encode.c
index cafe853..05d691d 100644
--- a/car/pb_encode.c
+++ b/car/pb_encode.c
@@ -27,6 +27,7 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
+static void *pb_const_cast(const void *p);
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
@@ -35,6 +36,7 @@ static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *f
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
+static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
/* --- Function pointers to field encoders ---
* Order in the array must match pb_action_t LTYPE numbering.
@@ -50,7 +52,7 @@ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
&pb_enc_string,
&pb_enc_submessage,
NULL, /* extensions */
- &pb_enc_bytes /* PB_LTYPE_FIXED_LENGTH_BYTES */
+ &pb_enc_fixed_length_bytes
};
/*******************************
@@ -202,32 +204,81 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
* This function implements the check for the zero value. */
static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData)
{
- if(PB_LTYPE(field->type) == PB_LTYPE_BYTES)
+ pb_type_t type = field->type;
+ const void *pSize = (const char*)pData + field->size_offset;
+
+ if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
+ {
+ /* Required proto2 fields inside proto3 submessage, pretty rare case */
+ return false;
+ }
+ else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
- const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData;
- return bytes->size == 0;
+ /* Repeated fields inside proto3 submessage: present if count != 0 */
+ return *(const pb_size_t*)pSize == 0;
}
- else if (PB_LTYPE(field->type) == PB_LTYPE_STRING)
+ else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
- return *(const char*)pData == '\0';
+ /* Oneof fields */
+ return *(const pb_size_t*)pSize == 0;
}
- else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES)
+ else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset)
{
- /* Fixed length bytes is only empty if its length is fixed
- * as 0. Which would be pretty strange, but we can check
- * it anyway. */
- return field->data_size == 0;
+ /* Proto2 optional fields inside proto3 submessage */
+ return *(const bool*)pSize == false;
}
- else
+
+ /* Rest is proto3 singular fields */
+
+ if (PB_ATYPE(type) == PB_ATYPE_STATIC)
+ {
+ if (PB_LTYPE(type) == PB_LTYPE_BYTES)
+ {
+ const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData;
+ return bytes->size == 0;
+ }
+ else if (PB_LTYPE(type) == PB_LTYPE_STRING)
+ {
+ return *(const char*)pData == '\0';
+ }
+ else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
+ {
+ /* Fixed length bytes is only empty if its length is fixed
+ * as 0. Which would be pretty strange, but we can check
+ * it anyway. */
+ return field->data_size == 0;
+ }
+ else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+ {
+ /* Check all fields in the submessage to find if any of them
+ * are non-zero. The comparison cannot be done byte-per-byte
+ * because the C struct may contain padding bytes that must
+ * be skipped.
+ */
+ pb_field_iter_t iter;
+ if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData)))
+ {
+ do
+ {
+ if (!pb_check_proto3_default_value(iter.pos, iter.pData))
+ {
+ return false;
+ }
+ } while (pb_field_iter_next(&iter));
+ }
+ return true;
+ }
+ }
+
{
- /* PB_LTYPE_VARINT, UVARINT, SVARINT, FIXED32, FIXED64,
- * SUBMESSAGE, EXTENSION: These all have integer or pointer
- * value which can be compared with 0. This does the check
- * byte-by-byte to avoid the switch-cast logic used in
- * pb_enc_varint(). (Casting to char* is safe with regards
- * to C strict aliasing rules.)
+ /* 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.
*/
- uint_fast8_t i;
+ pb_size_t i;
const char *p = (const char*)pData;
for (i = 0; i < field->data_size; i++)
{
@@ -411,7 +462,7 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream,
* Encode all fields *
*********************/
-static void *remove_const(const void *p)
+static void *pb_const_cast(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator
* logic for both encoding and decoding. */
@@ -426,7 +477,7 @@ static void *remove_const(const void *p)
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
{
pb_field_iter_t iter;
- if (!pb_field_iter_begin(&iter, fields, remove_const(src_struct)))
+ if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct)))
return true; /* Empty message type */
do {
@@ -694,9 +745,6 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie
{
const pb_bytes_array_t *bytes = NULL;
- if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES)
- return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size);
-
bytes = (const pb_bytes_array_t*)src;
if (src == NULL)
@@ -748,3 +796,8 @@ static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t
return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
}
+static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+{
+ return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size);
+}
+