X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=pb_encode.c;h=cd731dcf5df7d245d6e4275b632b9059091c89f5;hb=07375a126337916f3a34ea94f8085b8f89d789a1;hp=9f91c9d5f4473d08c16c4fd5d076c54bdffc813d;hpb=3b6099faa2d829c74c9576f4aa1ce4b237c997db;p=apps%2Fagl-service-can-low-level.git diff --git a/pb_encode.c b/pb_encode.c index 9f91c9d5..cd731dcf 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -35,6 +35,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. @@ -49,7 +50,8 @@ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { &pb_enc_bytes, &pb_enc_string, &pb_enc_submessage, - NULL /* extensions */ + NULL, /* extensions */ + &pb_enc_fixed_length_bytes }; /******************************* @@ -58,11 +60,12 @@ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) { + size_t i; pb_byte_t *dest = (pb_byte_t*)stream->state; stream->state = dest + count; - while (count--) - *dest++ = *buf++; + for (i = 0; i < count; i++) + dest[i] = buf[i]; return true; } @@ -196,21 +199,75 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie return true; } +/* In proto3, all fields are optional and are only encoded if their value is "non-zero". + * 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) + { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; + return bytes->size == 0; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_STRING) + { + return *(const char*)pData == '\0'; + } + else if (PB_LTYPE(field->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 + { + /* 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.) + */ + uint_fast8_t i; + const char *p = (const char*)pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } +} + /* Encode a field with static or pointer allocation, i.e. one whose data * is available to the encoder directly. */ static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData) { pb_encoder_t func; - const void *pSize; - bool implicit_has = true; + bool implicit_has; + const void *pSize = &implicit_has; func = PB_ENCODERS[PB_LTYPE(field->type)]; if (field->size_offset) + { + /* Static optional, repeated or oneof field */ pSize = (const char*)pData + field->size_offset; + } + else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) + { + /* Proto3 style field, optional but without explicit has_ field. */ + implicit_has = !pb_check_proto3_default_value(field, pData); + } else - pSize = &implicit_has; + { + /* Required field, always present */ + implicit_has = true; + } if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { @@ -218,7 +275,6 @@ static bool checkreturn encode_basic_field(pb_ostream_t *stream, * the data. If the 2nd pointer is NULL, it is interpreted as if * the has_field was false. */ - pData = *(const void* const*)pData; implicit_has = (pData != NULL); } @@ -498,6 +554,7 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t case PB_LTYPE_BYTES: case PB_LTYPE_STRING: case PB_LTYPE_SUBMESSAGE: + case PB_LTYPE_FIXED_LENGTH_BYTES: wiretype = PB_WT_STRING; break; @@ -636,11 +693,13 @@ static bool checkreturn pb_enc_fixed32(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) { - const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; + const pb_bytes_array_t *bytes = NULL; + + bytes = (const pb_bytes_array_t*)src; if (src == NULL) { - /* Threat null pointer as an empty bytes field */ + /* Treat null pointer as an empty bytes field */ return pb_encode_string(stream, NULL, 0); } @@ -664,7 +723,7 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi if (src == NULL) { - size = 0; /* Threat null pointer as an empty string */ + size = 0; /* Treat null pointer as an empty string */ } else { @@ -687,3 +746,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); +} +