From ee5b12c537115b113ce01708d4a86a4062cdb182 Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Sat, 21 Dec 2013 12:16:03 +0200 Subject: [PATCH] Add PB_LTYPE_UVARINT to fix encoding of negative int32 values. Apparently int32 values that are negative must be cast into int64 first before being encoded. Because uint32 still needs to be cast to uint64, the cases for int32 and uint32 had to be separated. Update issue 97 Status: FixedInGit --- pb.h | 30 +++++++++++++----------------- pb_decode.c | 24 +++++++++++++++++++++--- pb_encode.c | 23 +++++++++++++++++++++-- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/pb.h b/pb.h index 4e64dded..a8e95e59 100644 --- a/pb.h +++ b/pb.h @@ -116,11 +116,6 @@ /* List of possible field types. These are used in the autogenerated code. * Least-significant 4 bits tell the scalar type * Most-significant 4 bits specify repeated/required/packed etc. - * - * INT32 and UINT32 are treated the same, as are (U)INT64 and (S)FIXED* - * These types are simply casted to correct field type when they are - * assigned to the memory pointer. - * SINT* is different, though, because it is zig-zag coded. */ typedef uint8_t pb_type_t; @@ -128,32 +123,33 @@ typedef uint8_t pb_type_t; /**** Field data types ****/ /* Numeric types */ -#define PB_LTYPE_VARINT 0x00 /* int32, uint32, int64, uint64, bool, enum */ -#define PB_LTYPE_SVARINT 0x01 /* sint32, sint64 */ -#define PB_LTYPE_FIXED32 0x02 /* fixed32, sfixed32, float */ -#define PB_LTYPE_FIXED64 0x03 /* fixed64, sfixed64, double */ +#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */ /* Marker for last packable field type. */ -#define PB_LTYPE_LAST_PACKABLE 0x03 +#define PB_LTYPE_LAST_PACKABLE 0x04 /* Byte array with pre-allocated buffer. * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ -#define PB_LTYPE_BYTES 0x04 +#define PB_LTYPE_BYTES 0x05 /* String with pre-allocated buffer. * data_size is the maximum length. */ -#define PB_LTYPE_STRING 0x05 +#define PB_LTYPE_STRING 0x06 /* Submessage * submsg_fields is pointer to field descriptions */ -#define PB_LTYPE_SUBMESSAGE 0x06 +#define PB_LTYPE_SUBMESSAGE 0x07 /* Extension pseudo-field * The field contains a pointer to pb_extension_t */ -#define PB_LTYPE_EXTENSION 0x07 +#define PB_LTYPE_EXTENSION 0x08 /* Number of declared LTYPES */ -#define PB_LTYPES_COUNT 8 +#define PB_LTYPES_COUNT 9 #define PB_LTYPE_MASK 0x0F /**** Field repetition rules ****/ @@ -410,8 +406,8 @@ struct _pb_extension_t { #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_VARINT -#define PB_LTYPE_MAP_UINT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT #define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION /* This is the actual macro used in field descriptions. diff --git a/pb_decode.c b/pb_decode.c index a887d155..30c124dd 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -47,7 +47,8 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_exten static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn find_extension_field(pb_field_iterator_t *iter); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); -static bool pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); @@ -62,6 +63,7 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream); */ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { &pb_dec_varint, + &pb_dec_uvarint, &pb_dec_svarint, &pb_dec_fixed32, &pb_dec_fixed64, @@ -823,8 +825,24 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo switch (field->data_size) { - case 1: *(uint8_t*)dest = (uint8_t)value; break; - case 2: *(uint16_t*)dest = (uint16_t)value; break; + case 1: *(int8_t*)dest = (int8_t)value; break; + case 2: *(int16_t*)dest = (int16_t)value; break; + case 4: *(int32_t*)dest = (int32_t)value; break; + case 8: *(int64_t*)dest = (int64_t)value; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return true; +} + +bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + switch (field->data_size) + { case 4: *(uint32_t*)dest = (uint32_t)value; break; case 8: *(uint64_t*)dest = value; break; default: PB_RETURN_ERROR(stream, "invalid data_size"); diff --git a/pb_encode.c b/pb_encode.c index ebf20de5..f6e08a57 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -28,6 +28,7 @@ static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *fie 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 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); static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); @@ -40,6 +41,7 @@ static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t */ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { &pb_enc_varint, + &pb_enc_uvarint, &pb_enc_svarint, &pb_enc_fixed32, &pb_enc_fixed64, @@ -424,6 +426,7 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t switch (PB_LTYPE(field->type)) { case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: case PB_LTYPE_SVARINT: wiretype = PB_WT_VARINT; break; @@ -505,13 +508,29 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie /* Field encoders */ bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + int64_t value = 0; + + /* Cases 1 and 2 are for compilers that have smaller types for bool + * or enums. */ + switch (field->data_size) + { + case 1: value = *(const int8_t*)src; break; + case 2: value = *(const int16_t*)src; break; + case 4: value = *(const int32_t*)src; break; + case 8: value = *(const int64_t*)src; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return pb_encode_varint(stream, (uint64_t)value); +} + +bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { uint64_t value = 0; switch (field->data_size) { - case 1: value = *(const uint8_t*)src; break; - case 2: value = *(const uint16_t*)src; break; case 4: value = *(const uint32_t*)src; break; case 8: value = *(const uint64_t*)src; break; default: PB_RETURN_ERROR(stream, "invalid data_size"); -- 2.16.6