From 8a17ac55a2ebfe7eb325522e8a4635b83a2f957b Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 11 Dec 2017 00:32:34 +0100 Subject: sync --- elegoo/pb/pb_decode.c | 119 +++++++++++++++++++++++++++++++++++++++----------- elegoo/pb/pb_decode.h | 22 ++++++++++ elegoo/pb/pb_encode.c | 97 ++++++++++++++++++++++++++++++++-------- elegoo/pb/pb_encode.h | 16 +++++++ 4 files changed, 209 insertions(+), 45 deletions(-) (limited to 'elegoo') diff --git a/elegoo/pb/pb_decode.c b/elegoo/pb/pb_decode.c index b4563cf..dc344dc 100644 --- a/elegoo/pb/pb_decode.c +++ b/elegoo/pb/pb_decode.c @@ -35,6 +35,7 @@ static bool checkreturn find_extension_field(pb_field_iter_t *iter); static void pb_field_set_to_default(pb_field_iter_t *iter); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); 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); @@ -52,6 +53,14 @@ static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_it static void pb_release_single_field(const pb_field_iter_t *iter); #endif +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + /* --- Function pointers to field decoders --- * Order in the array must match pb_action_t LTYPE numbering. */ @@ -170,13 +179,23 @@ pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) * Helper functions * ********************/ -bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof) { pb_byte_t byte; uint32_t result; if (!pb_readbyte(stream, &byte)) + { + if (stream->bytes_left == 0) + { + if (eof) + { + *eof = true; + } + } + return false; + } if ((byte & 0x80) == 0) { @@ -191,21 +210,43 @@ bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) do { - if (bitpos >= 32) - PB_RETURN_ERROR(stream, "varint overflow"); - if (!pb_readbyte(stream, &byte)) return false; - result |= (uint32_t)(byte & 0x7F) << bitpos; + if (bitpos >= 32) + { + /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ + uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; + + if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) + { + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + else + { + result |= (uint32_t)(byte & 0x7F) << bitpos; + } bitpos = (uint_fast8_t)(bitpos + 7); } while (byte & 0x80); + + if (bitpos == 35 && (byte & 0x70) != 0) + { + /* The last byte was at bitpos=28, so only bottom 4 bits fit. */ + PB_RETURN_ERROR(stream, "varint overflow"); + } } *dest = result; return true; } +bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +{ + return pb_decode_varint32_eof(stream, dest, NULL); +} + +#ifndef PB_WITHOUT_64BIT bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) { pb_byte_t byte; @@ -227,6 +268,7 @@ bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) *dest = result; return true; } +#endif bool checkreturn pb_skip_varint(pb_istream_t *stream) { @@ -255,11 +297,8 @@ bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, *wire_type = (pb_wire_type_t) 0; *tag = 0; - if (!pb_decode_varint32(stream, &temp)) + if (!pb_decode_varint32_eof(stream, &temp, eof)) { - if (stream->bytes_left == 0) - *eof = true; - return false; } @@ -978,6 +1017,21 @@ bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void return status; } +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode_noinit(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) { pb_istream_t substream; @@ -993,6 +1047,12 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * return status; } +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ + return pb_decode(stream, fields, dest_struct); +} + #ifdef PB_ENABLE_MALLOC /* Given an oneof field, if there has already been a field inside this oneof, * release it before overwriting with a different one. */ @@ -1127,16 +1187,16 @@ void pb_release(const pb_field_t fields[], void *dest_struct) /* Field decoders */ -bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) +bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) { - uint64_t value; + pb_uint64_t value; if (!pb_decode_varint(stream, &value)) return false; if (value & 1) - *dest = (int64_t)(~(value >> 1)); + *dest = (pb_int64_t)(~(value >> 1)); else - *dest = (int64_t)(value >> 1); + *dest = (pb_int64_t)(value >> 1); return true; } @@ -1155,6 +1215,7 @@ bool pb_decode_fixed32(pb_istream_t *stream, void *dest) return true; } +#ifndef PB_WITHOUT_64BIT bool pb_decode_fixed64(pb_istream_t *stream, void *dest) { pb_byte_t bytes[8]; @@ -1173,12 +1234,13 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest) return true; } +#endif static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) { - uint64_t value; - int64_t svalue; - int64_t clamped; + pb_uint64_t value; + pb_int64_t svalue; + pb_int64_t clamped; if (!pb_decode_varint(stream, &value)) return false; @@ -1188,14 +1250,14 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *fi * not break decoding of such messages, we cast <=32 bit fields to * int32_t first to get the sign correct. */ - if (field->data_size == sizeof(int64_t)) - svalue = (int64_t)value; + if (field->data_size == sizeof(pb_int64_t)) + svalue = (pb_int64_t)value; else svalue = (int32_t)value; /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(int64_t)) - clamped = *(int64_t*)dest = svalue; + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = svalue; else if (field->data_size == sizeof(int32_t)) clamped = *(int32_t*)dest = (int32_t)svalue; else if (field->data_size == sizeof(int_least16_t)) @@ -1213,13 +1275,13 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *fi static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) { - uint64_t value, clamped; + pb_uint64_t value, clamped; if (!pb_decode_varint(stream, &value)) return false; /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(uint64_t)) - clamped = *(uint64_t*)dest = value; + if (field->data_size == sizeof(pb_uint64_t)) + clamped = *(pb_uint64_t*)dest = value; else if (field->data_size == sizeof(uint32_t)) clamped = *(uint32_t*)dest = (uint32_t)value; else if (field->data_size == sizeof(uint_least16_t)) @@ -1237,13 +1299,13 @@ static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *f static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) { - int64_t value, clamped; + pb_int64_t value, clamped; if (!pb_decode_svarint(stream, &value)) return false; /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(int64_t)) - clamped = *(int64_t*)dest = value; + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = value; else if (field->data_size == sizeof(int32_t)) clamped = *(int32_t*)dest = (int32_t)value; else if (field->data_size == sizeof(int_least16_t)) @@ -1268,7 +1330,12 @@ static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *f static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) { PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT return pb_decode_fixed64(stream, dest); +#else + PB_UNUSED(dest); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif } static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) diff --git a/elegoo/pb/pb_decode.h b/elegoo/pb/pb_decode.h index a426bdd..398b24a 100644 --- a/elegoo/pb/pb_decode.h +++ b/elegoo/pb/pb_decode.h @@ -85,6 +85,18 @@ bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *des */ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +/* Same as pb_decode_delimited, except that it does not initialize the destination structure. + * See pb_decode_noinit + */ +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except allows the message to be terminated with a null byte. + * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour + * is not supported in most other protobuf implementations, so pb_decode_delimited() + * is a better option for compatibility. + */ +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + #ifdef PB_ENABLE_MALLOC /* Release any allocated pointer fields. If you use dynamic allocation, you should * call this for any successfully decoded message when you are done with it. If @@ -124,7 +136,11 @@ bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); /* Decode an integer in the varint format. This works for bool, enum, int32, * int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); +#else +#define pb_decode_varint pb_decode_varint32 +#endif /* Decode an integer in the varint format. This works for bool, enum, int32, * and uint32 field types. */ @@ -132,15 +148,21 @@ bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); /* Decode an integer in the zig-zagged svarint format. This works for sint32 * and sint64. */ +#ifndef PB_WITHOUT_64BIT bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); +#else +bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest); +#endif /* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to * a 4-byte wide C variable. */ bool pb_decode_fixed32(pb_istream_t *stream, void *dest); +#ifndef PB_WITHOUT_64BIT /* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to * a 8-byte wide C variable. */ bool pb_decode_fixed64(pb_istream_t *stream, void *dest); +#endif /* Make a limited-length substream for reading a PB_WT_STRING field. */ bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); diff --git a/elegoo/pb/pb_encode.c b/elegoo/pb/pb_encode.c index 05d691d..b67b79b 100644 --- a/elegoo/pb/pb_encode.c +++ b/elegoo/pb/pb_encode.c @@ -38,6 +38,16 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi 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); +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t + +static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value); +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + /* --- Function pointers to field encoders --- * Order in the array must match pb_action_t LTYPE numbering. */ @@ -154,7 +164,7 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie size = sizestream.bytes_written; } - if (!pb_encode_varint(stream, (uint64_t)size)) + if (!pb_encode_varint(stream, (pb_uint64_t)size)) return false; if (stream->callback == NULL) @@ -503,6 +513,16 @@ bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const return pb_encode_submessage(stream, fields, src_struct); } +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + const pb_byte_t zero = 0; + + if (!pb_encode(stream, fields, src_struct)) + return false; + + return pb_write(stream, &zero, 1); +} + bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) { pb_ostream_t stream = PB_OSTREAM_SIZING; @@ -517,7 +537,34 @@ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *sr /******************** * Helper functions * ********************/ -bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) + +#ifdef PB_WITHOUT_64BIT +bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */ + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + if (compensation) + { + /* re-set all the compensation bits we can or need */ + size_t bits = compensation > 7 ? 7 : compensation; + value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */ + compensation -= bits; + } + i++; + } + buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} +#endif + +bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) { pb_byte_t buffer[10]; size_t i = 0; @@ -539,13 +586,13 @@ bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) return pb_write(stream, buffer, i); } -bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) { - uint64_t zigzagged; + pb_uint64_t zigzagged; if (value < 0) - zigzagged = ~((uint64_t)value << 1); + zigzagged = ~((pb_uint64_t)value << 1); else - zigzagged = (uint64_t)value << 1; + zigzagged = (pb_uint64_t)value << 1; return pb_encode_varint(stream, zigzagged); } @@ -561,6 +608,7 @@ bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) return pb_write(stream, bytes, 4); } +#ifndef PB_WITHOUT_64BIT bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) { uint64_t val = *(const uint64_t*)value; @@ -575,10 +623,11 @@ bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); return pb_write(stream, bytes, 8); } +#endif bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) { - uint64_t tag = ((uint64_t)field_number << 3) | wiretype; + pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; return pb_encode_varint(stream, tag); } @@ -617,7 +666,7 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) { - if (!pb_encode_varint(stream, (uint64_t)size)) + if (!pb_encode_varint(stream, (pb_uint64_t)size)) return false; return pb_write(stream, buffer, size); @@ -640,7 +689,7 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie size = substream.bytes_written; - if (!pb_encode_varint(stream, (uint64_t)size)) + if (!pb_encode_varint(stream, (pb_uint64_t)size)) return false; if (stream->callback == NULL) @@ -677,7 +726,7 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - int64_t value = 0; + pb_int64_t value = 0; if (field->data_size == sizeof(int_least8_t)) value = *(const int_least8_t*)src; @@ -685,17 +734,22 @@ static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *fi value = *(const int_least16_t*)src; else if (field->data_size == sizeof(int32_t)) value = *(const int32_t*)src; - else if (field->data_size == sizeof(int64_t)) - value = *(const int64_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; else PB_RETURN_ERROR(stream, "invalid data_size"); - return pb_encode_varint(stream, (uint64_t)value); +#ifdef PB_WITHOUT_64BIT + if (value < 0) + return pb_encode_negative_varint(stream, (pb_uint64_t)value); + else +#endif + return pb_encode_varint(stream, (pb_uint64_t)value); } static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - uint64_t value = 0; + pb_uint64_t value = 0; if (field->data_size == sizeof(uint_least8_t)) value = *(const uint_least8_t*)src; @@ -703,8 +757,8 @@ static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *f value = *(const uint_least16_t*)src; else if (field->data_size == sizeof(uint32_t)) value = *(const uint32_t*)src; - else if (field->data_size == sizeof(uint64_t)) - value = *(const uint64_t*)src; + else if (field->data_size == sizeof(pb_uint64_t)) + value = *(const pb_uint64_t*)src; else PB_RETURN_ERROR(stream, "invalid data_size"); @@ -713,7 +767,7 @@ static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *f static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - int64_t value = 0; + pb_int64_t value = 0; if (field->data_size == sizeof(int_least8_t)) value = *(const int_least8_t*)src; @@ -721,8 +775,8 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f value = *(const int_least16_t*)src; else if (field->data_size == sizeof(int32_t)) value = *(const int32_t*)src; - else if (field->data_size == sizeof(int64_t)) - value = *(const int64_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; else PB_RETURN_ERROR(stream, "invalid data_size"); @@ -732,7 +786,12 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) { PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT return pb_encode_fixed64(stream, src); +#else + PB_UNUSED(src); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif } static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) diff --git a/elegoo/pb/pb_encode.h b/elegoo/pb/pb_encode.h index d9909fb..8bf78dd 100644 --- a/elegoo/pb/pb_encode.h +++ b/elegoo/pb/pb_encode.h @@ -71,6 +71,12 @@ bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_ */ bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); +/* Same as pb_encode, but appends a null byte to the message for termination. + * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() + * is a better option for compatibility. + */ +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + /* Encode the message to get the size of the encoded data, but do not store * the data. */ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); @@ -123,11 +129,19 @@ bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field /* Encode an integer in the varint format. * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); +#else +bool pb_encode_varint(pb_ostream_t *stream, uint32_t value); +#endif /* Encode an integer in the zig-zagged svarint format. * This works for sint32 and sint64. */ +#ifndef PB_WITHOUT_64BIT bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); +#else +bool pb_encode_svarint(pb_ostream_t *stream, int32_t value); +#endif /* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); @@ -136,9 +150,11 @@ bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size * You need to pass a pointer to a 4-byte wide C variable. */ bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); +#ifndef PB_WITHOUT_64BIT /* Encode a fixed64, sfixed64 or double value. * You need to pass a pointer to a 8-byte wide C variable. */ bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); +#endif /* Encode a submessage field. * You need to pass the pb_field_t array and pointer to struct, just like -- cgit v1.2.3