diff options
author | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2017-09-16 09:28:08 +0300 |
---|---|---|
committer | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2017-09-16 09:28:08 +0300 |
commit | c291fee05f0fee96a2e0eabfbb8ee7b62ac12cfb (patch) | |
tree | d9d525f44ff9bb2cd2ea11db761833fb29756283 | |
parent | 64668e3aa187fc4c0358f9665626ae1242e48b08 (diff) |
Add option to build without 64-bit support (issue #86)
-rw-r--r-- | docs/reference.rst | 2 | ||||
-rw-r--r-- | pb.h | 2 | ||||
-rw-r--r-- | pb_decode.c | 60 | ||||
-rw-r--r-- | pb_decode.h | 10 | ||||
-rw-r--r-- | pb_encode.c | 53 | ||||
-rw-r--r-- | pb_encode.h | 10 | ||||
-rw-r--r-- | tests/without_64bit/SConscript | 31 | ||||
-rw-r--r-- | tests/without_64bit/alltypes.options | 3 | ||||
-rw-r--r-- | tests/without_64bit/alltypes.proto | 100 | ||||
-rw-r--r-- | tests/without_64bit/decode_alltypes.c | 185 | ||||
-rw-r--r-- | tests/without_64bit/encode_alltypes.c | 124 | ||||
-rw-r--r-- | tests/without_64bit/no_64bit_syshdr.h | 17 |
12 files changed, 557 insertions, 40 deletions
diff --git a/docs/reference.rst b/docs/reference.rst index 77d1bda..5ee332e 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -53,6 +53,8 @@ PB_SYSTEM_HEADER Replace the standard header files with a single functions and typedefs listed on the `overview page`_. Value must include quotes, for example *#define PB_SYSTEM_HEADER "foo.h"*. +PB_WITHOUT_64BIT Disable 64-bit support, for old compilers or + for a slight speedup on 8-bit platforms. ============================ ================================================ The PB_MAX_REQUIRED_FIELDS, PB_FIELD_16BIT and PB_FIELD_32BIT settings allow @@ -251,8 +251,10 @@ PB_PACKED_STRUCT_END * If you get errors here, it probably means that your stdint.h is not * correct for your platform. */ +#ifndef PB_WITHOUT_64BIT PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE) PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) +#endif /* This structure is used for 'bytes' arrays. * It has the number of bytes in the beginning, and after that an array. diff --git a/pb_decode.c b/pb_decode.c index 60a9ae9..4a65758 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -53,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. */ @@ -207,9 +215,10 @@ static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *d if (bitpos >= 32) { - /* Note: Technically, the varint could have trailing 0x80 bytes, even - * though I haven't seen any implementation do that yet. */ - if ((byte & 0x7F) != 0) + /* 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"); } @@ -221,7 +230,7 @@ static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *d bitpos = (uint_fast8_t)(bitpos + 7); } while (byte & 0x80); - if (bitpos >= 32 && (byte & 0x70) != 0) + 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"); @@ -237,6 +246,7 @@ 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; @@ -258,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) { @@ -1155,16 +1166,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; } @@ -1183,6 +1194,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]; @@ -1201,12 +1213,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; @@ -1216,14 +1229,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)) @@ -1241,13 +1254,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)) @@ -1265,13 +1278,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)) @@ -1296,7 +1309,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/pb_decode.h b/pb_decode.h index a426bdd..4fe7995 100644 --- a/pb_decode.h +++ b/pb_decode.h @@ -124,7 +124,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 +136,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/pb_encode.c b/pb_encode.c index 05d691d..2ff8f1d 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -38,6 +38,14 @@ 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 +#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 +162,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) @@ -517,7 +525,7 @@ 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) +bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) { pb_byte_t buffer[10]; size_t i = 0; @@ -539,13 +547,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 +569,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 +584,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 +627,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 +650,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 +687,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 +695,17 @@ 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); + 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 +713,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 +723,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 +731,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 +742,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/pb_encode.h b/pb_encode.h index d9909fb..d18a72d 100644 --- a/pb_encode.h +++ b/pb_encode.h @@ -123,11 +123,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 +144,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 diff --git a/tests/without_64bit/SConscript b/tests/without_64bit/SConscript new file mode 100644 index 0000000..35df25b --- /dev/null +++ b/tests/without_64bit/SConscript @@ -0,0 +1,31 @@ +# Run the alltypes test case, but compile with PB_WITHOUT_64BIT. + +Import("env") + +env.NanopbProto(["alltypes", "alltypes.options"]) + +# Define the compilation options +opts = env.Clone() +opts.Append(CPPDEFINES = {'PB_WITHOUT_64BIT': 1, 'HAVE_STDINT_H': 0, 'PB_SYSTEM_HEADER': '\\"no_64bit_syshdr.h\\"'}) +opts['CFLAGS'] = str(opts['CFLAGS']).replace('-Wno-long-long', '') +opts.Append(CPPPATH = "#without_64bit") + +if 'SYSHDR' in opts: + opts.Append(CPPDEFINES = {'PB_OLD_SYSHDR': opts['SYSHDR']}) + +# Build new version of core +strict = opts.Clone() +strict.Append(CFLAGS = strict['CORECFLAGS']) +strict.Object("pb_decode_no64bit.o", "$NANOPB/pb_decode.c") +strict.Object("pb_encode_no64bit.o", "$NANOPB/pb_encode.c") +strict.Object("pb_common_no64bit.o", "$NANOPB/pb_common.c") + +# Now build and run the test normally. +enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_no64bit.o", "pb_common_no64bit.o"]) +dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_no64bit.o", "pb_common_no64bit.o"]) + +env.RunTest(enc) +env.RunTest([dec, "encode_alltypes.output"]) + +env.RunTest("optionals.output", enc, ARGS = ['1']) +env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1']) diff --git a/tests/without_64bit/alltypes.options b/tests/without_64bit/alltypes.options new file mode 100644 index 0000000..0d5ab12 --- /dev/null +++ b/tests/without_64bit/alltypes.options @@ -0,0 +1,3 @@ +* max_size:16 +* max_count:5 +*.*fbytes fixed_length:true max_size:4 diff --git a/tests/without_64bit/alltypes.proto b/tests/without_64bit/alltypes.proto new file mode 100644 index 0000000..240685b --- /dev/null +++ b/tests/without_64bit/alltypes.proto @@ -0,0 +1,100 @@ +syntax = "proto2"; +// package name placeholder + +message SubMessage { + required string substuff1 = 1 [default = "1"]; + required int32 substuff2 = 2 [default = 2]; + optional fixed32 substuff3 = 3 [default = 3]; +} + +message EmptyMessage { + +} + +enum HugeEnum { + Negative = -2147483647; /* protoc doesn't accept -2147483648 here */ + Positive = 2147483647; +} + +message Limits { + required int32 int32_min = 1 [default = 2147483647]; + required int32 int32_max = 2 [default = -2147483647]; + required uint32 uint32_min = 3 [default = 4294967295]; + required uint32 uint32_max = 4 [default = 0]; + required HugeEnum enum_min = 9 [default = Positive]; + required HugeEnum enum_max = 10 [default = Negative]; +} + +enum MyEnum { + Zero = 0; + First = 1; + Second = 2; + Truth = 42; +} + +message AllTypes { + required int32 req_int32 = 1; + required uint32 req_uint32 = 3; + required sint32 req_sint32 = 5; + required bool req_bool = 7; + + required fixed32 req_fixed32 = 8; + required sfixed32 req_sfixed32= 9; + required float req_float = 10; + + required string req_string = 14; + required bytes req_bytes = 15; + required SubMessage req_submsg = 16; + required MyEnum req_enum = 17; + required EmptyMessage req_emptymsg = 18; + required bytes req_fbytes = 19; + + repeated int32 rep_int32 = 21 [packed = true]; + repeated uint32 rep_uint32 = 23 [packed = true]; + repeated sint32 rep_sint32 = 25 [packed = true]; + repeated bool rep_bool = 27 [packed = true]; + + repeated fixed32 rep_fixed32 = 28 [packed = true]; + repeated sfixed32 rep_sfixed32= 29 [packed = true]; + repeated float rep_float = 30 [packed = true]; + + repeated string rep_string = 34; + repeated bytes rep_bytes = 35; + repeated SubMessage rep_submsg = 36; + repeated MyEnum rep_enum = 37 [packed = true]; + repeated EmptyMessage rep_emptymsg = 38; + repeated bytes rep_fbytes = 39; + + optional int32 opt_int32 = 41 [default = 4041]; + optional uint32 opt_uint32 = 43 [default = 4043]; + optional sint32 opt_sint32 = 45 [default = 4045]; + optional bool opt_bool = 47 [default = false]; + + optional fixed32 opt_fixed32 = 48 [default = 4048]; + optional sfixed32 opt_sfixed32= 49 [default = 4049]; + optional float opt_float = 50 [default = 4050]; + + optional string opt_string = 54 [default = "4054"]; + optional bytes opt_bytes = 55 [default = "4055"]; + optional SubMessage opt_submsg = 56; + optional MyEnum opt_enum = 57 [default = Second]; + optional EmptyMessage opt_emptymsg = 58; + optional bytes opt_fbytes = 59 [default = "4059"]; + + oneof oneof + { + SubMessage oneof_msg1 = 60; + EmptyMessage oneof_msg2 = 61; + } + + // Check that extreme integer values are handled correctly + required Limits req_limits = 98; + + // Just to make sure that the size of the fields has been calculated + // properly, i.e. otherwise a bug in last field might not be detected. + required int32 end = 99; + + + extensions 200 to 255; +} + diff --git a/tests/without_64bit/decode_alltypes.c b/tests/without_64bit/decode_alltypes.c new file mode 100644 index 0000000..6b5ff8e --- /dev/null +++ b/tests/without_64bit/decode_alltypes.c @@ -0,0 +1,185 @@ +/* Tests the decoding of all types. + * This is the counterpart of test_encode3. + * Run e.g. ./test_encode3 | ./test_decode3 + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <pb_decode.h> +#include "alltypes.pb.h" +#include "test_helpers.h" + +#define TEST(x) if (!(x)) { \ + printf("Test " #x " failed.\n"); \ + return false; \ + } + +/* This function is called once from main(), it handles + the decoding and checks the fields. */ +bool check_alltypes(pb_istream_t *stream, int mode) +{ + /* Uses _init_default to just make sure that it works. */ + AllTypes alltypes = AllTypes_init_default; + + /* Fill with garbage to better detect initialization errors */ + memset(&alltypes, 0xAA, sizeof(alltypes)); + alltypes.extensions = 0; + + if (!pb_decode(stream, AllTypes_fields, &alltypes)) + return false; + + TEST(alltypes.req_int32 == -1001); + TEST(alltypes.req_uint32 == 1003); + TEST(alltypes.req_sint32 == -1005); + TEST(alltypes.req_bool == true); + + TEST(alltypes.req_fixed32 == 1008); + TEST(alltypes.req_sfixed32 == -1009); + TEST(alltypes.req_float == 1010.0f); + + TEST(strcmp(alltypes.req_string, "1014") == 0); + TEST(alltypes.req_bytes.size == 4); + TEST(memcmp(alltypes.req_bytes.bytes, "1015", 4) == 0); + TEST(strcmp(alltypes.req_submsg.substuff1, "1016") == 0); + TEST(alltypes.req_submsg.substuff2 == 1016); + TEST(alltypes.req_submsg.substuff3 == 3); + TEST(alltypes.req_enum == MyEnum_Truth); + TEST(memcmp(alltypes.req_fbytes, "1019", 4) == 0); + + TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0); + TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0); + TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0); + TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false); + + TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0); + TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0); + TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f); + + TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0'); + TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4].size == 4 && alltypes.rep_bytes[0].size == 0); + TEST(memcmp(alltypes.rep_bytes[4].bytes, "2015", 4) == 0); + + TEST(alltypes.rep_submsg_count == 5); + TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0'); + TEST(alltypes.rep_submsg[4].substuff2 == 2016 && alltypes.rep_submsg[0].substuff2 == 0); + TEST(alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == 3); + + TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero); + TEST(alltypes.rep_emptymsg_count == 5); + TEST(alltypes.rep_fbytes_count == 5); + TEST(alltypes.rep_fbytes[0][0] == 0 && alltypes.rep_fbytes[0][3] == 0); + TEST(memcmp(alltypes.rep_fbytes[4], "2019", 4) == 0); + + if (mode == 0) + { + /* Expect default values */ + TEST(alltypes.has_opt_int32 == false); + TEST(alltypes.opt_int32 == 4041); + TEST(alltypes.has_opt_uint32 == false); + TEST(alltypes.opt_uint32 == 4043); + TEST(alltypes.has_opt_sint32 == false); + TEST(alltypes.opt_sint32 == 4045); + TEST(alltypes.has_opt_bool == false); + TEST(alltypes.opt_bool == false); + + TEST(alltypes.has_opt_fixed32 == false); + TEST(alltypes.opt_fixed32 == 4048); + TEST(alltypes.has_opt_sfixed32 == false); + TEST(alltypes.opt_sfixed32 == 4049); + TEST(alltypes.has_opt_float == false); + TEST(alltypes.opt_float == 4050.0f); + + TEST(alltypes.has_opt_string == false); + TEST(strcmp(alltypes.opt_string, "4054") == 0); + TEST(alltypes.has_opt_bytes == false); + TEST(alltypes.opt_bytes.size == 4); + TEST(memcmp(alltypes.opt_bytes.bytes, "4055", 4) == 0); + TEST(alltypes.has_opt_submsg == false); + TEST(strcmp(alltypes.opt_submsg.substuff1, "1") == 0); + TEST(alltypes.opt_submsg.substuff2 == 2); + TEST(alltypes.opt_submsg.substuff3 == 3); + TEST(alltypes.has_opt_enum == false); + TEST(alltypes.opt_enum == MyEnum_Second); + TEST(alltypes.has_opt_emptymsg == false); + TEST(alltypes.has_opt_fbytes == false); + TEST(memcmp(alltypes.opt_fbytes, "4059", 4) == 0); + + TEST(alltypes.which_oneof == 0); + } + else + { + /* Expect filled-in values */ + TEST(alltypes.has_opt_int32 == true); + TEST(alltypes.opt_int32 == 3041); + TEST(alltypes.has_opt_uint32 == true); + TEST(alltypes.opt_uint32 == 3043); + TEST(alltypes.has_opt_sint32 == true); + TEST(alltypes.opt_sint32 == 3045); + TEST(alltypes.has_opt_bool == true); + TEST(alltypes.opt_bool == true); + + TEST(alltypes.has_opt_fixed32 == true); + TEST(alltypes.opt_fixed32 == 3048); + TEST(alltypes.has_opt_sfixed32 == true); + TEST(alltypes.opt_sfixed32 == 3049); + TEST(alltypes.has_opt_float == true); + TEST(alltypes.opt_float == 3050.0f); + + TEST(alltypes.has_opt_string == true); + TEST(strcmp(alltypes.opt_string, "3054") == 0); + TEST(alltypes.has_opt_bytes == true); + TEST(alltypes.opt_bytes.size == 4); + TEST(memcmp(alltypes.opt_bytes.bytes, "3055", 4) == 0); + TEST(alltypes.has_opt_submsg == true); + TEST(strcmp(alltypes.opt_submsg.substuff1, "3056") == 0); + TEST(alltypes.opt_submsg.substuff2 == 3056); + TEST(alltypes.opt_submsg.substuff3 == 3); + TEST(alltypes.has_opt_enum == true); + TEST(alltypes.opt_enum == MyEnum_Truth); + TEST(alltypes.has_opt_emptymsg == true); + TEST(alltypes.has_opt_fbytes == true); + TEST(memcmp(alltypes.opt_fbytes, "3059", 4) == 0); + + TEST(alltypes.which_oneof == AllTypes_oneof_msg1_tag); + TEST(strcmp(alltypes.oneof.oneof_msg1.substuff1, "4059") == 0); + TEST(alltypes.oneof.oneof_msg1.substuff2 == 4059); + } + + TEST(alltypes.req_limits.int32_min == INT32_MIN); + TEST(alltypes.req_limits.int32_max == INT32_MAX); + TEST(alltypes.req_limits.uint32_min == 0); + TEST(alltypes.req_limits.uint32_max == UINT32_MAX); + TEST(alltypes.req_limits.enum_min == HugeEnum_Negative); + TEST(alltypes.req_limits.enum_max == HugeEnum_Positive); + + TEST(alltypes.end == 1099); + + return true; +} + +int main(int argc, char **argv) +{ + uint8_t buffer[1024]; + size_t count; + pb_istream_t stream; + + /* Whether to expect the optional values or the default values. */ + int mode = (argc > 1) ? atoi(argv[1]) : 0; + + /* Read the data into buffer */ + SET_BINARY_MODE(stdin); + count = fread(buffer, 1, sizeof(buffer), stdin); + + /* Construct a pb_istream_t for reading from the buffer */ + stream = pb_istream_from_buffer(buffer, count); + + /* Decode and print out the stuff */ + if (!check_alltypes(&stream, mode)) + { + printf("Parsing failed: %s\n", PB_GET_ERROR(&stream)); + return 1; + } else { + return 0; + } +} diff --git a/tests/without_64bit/encode_alltypes.c b/tests/without_64bit/encode_alltypes.c new file mode 100644 index 0000000..9fe26f6 --- /dev/null +++ b/tests/without_64bit/encode_alltypes.c @@ -0,0 +1,124 @@ +/* Attempts to test all the datatypes supported by ProtoBuf. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pb_encode.h> +#include "alltypes.pb.h" +#include "test_helpers.h" + +int main(int argc, char **argv) +{ + int mode = (argc > 1) ? atoi(argv[1]) : 0; + + /* Initialize the structure with constants */ + AllTypes alltypes = AllTypes_init_zero; + + alltypes.req_int32 = -1001; + alltypes.req_uint32 = 1003; + alltypes.req_sint32 = -1005; + alltypes.req_bool = true; + + alltypes.req_fixed32 = 1008; + alltypes.req_sfixed32 = -1009; + alltypes.req_float = 1010.0f; + + strcpy(alltypes.req_string, "1014"); + alltypes.req_bytes.size = 4; + memcpy(alltypes.req_bytes.bytes, "1015", 4); + strcpy(alltypes.req_submsg.substuff1, "1016"); + alltypes.req_submsg.substuff2 = 1016; + alltypes.req_enum = MyEnum_Truth; + memcpy(alltypes.req_fbytes, "1019", 4); + + alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001; + alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003; + alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005; + alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true; + + alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008; + alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009; + alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f; + + alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014"); + alltypes.rep_bytes_count = 5; alltypes.rep_bytes[4].size = 4; + memcpy(alltypes.rep_bytes[4].bytes, "2015", 4); + + alltypes.rep_submsg_count = 5; + strcpy(alltypes.rep_submsg[4].substuff1, "2016"); + alltypes.rep_submsg[4].substuff2 = 2016; + alltypes.rep_submsg[4].has_substuff3 = true; + alltypes.rep_submsg[4].substuff3 = 2016; + + alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth; + alltypes.rep_emptymsg_count = 5; + + alltypes.rep_fbytes_count = 5; + memcpy(alltypes.rep_fbytes[4], "2019", 4); + + alltypes.req_limits.int32_min = INT32_MIN; + alltypes.req_limits.int32_max = INT32_MAX; + alltypes.req_limits.uint32_min = 0; + alltypes.req_limits.uint32_max = UINT32_MAX; + alltypes.req_limits.enum_min = HugeEnum_Negative; + alltypes.req_limits.enum_max = HugeEnum_Positive; + + if (mode != 0) + { + /* Fill in values for optional fields */ + alltypes.has_opt_int32 = true; + alltypes.opt_int32 = 3041; + alltypes.has_opt_uint32 = true; + alltypes.opt_uint32 = 3043; + alltypes.has_opt_sint32 = true; + alltypes.opt_sint32 = 3045; + alltypes.has_opt_bool = true; + alltypes.opt_bool = true; + + alltypes.has_opt_fixed32 = true; + alltypes.opt_fixed32 = 3048; + alltypes.has_opt_sfixed32 = true; + alltypes.opt_sfixed32 = 3049; + alltypes.has_opt_float = true; + alltypes.opt_float = 3050.0f; + + alltypes.has_opt_string = true; + strcpy(alltypes.opt_string, "3054"); + alltypes.has_opt_bytes = true; + alltypes.opt_bytes.size = 4; + memcpy(alltypes.opt_bytes.bytes, "3055", 4); + alltypes.has_opt_submsg = true; + strcpy(alltypes.opt_submsg.substuff1, "3056"); + alltypes.opt_submsg.substuff2 = 3056; + alltypes.has_opt_enum = true; + alltypes.opt_enum = MyEnum_Truth; + alltypes.has_opt_emptymsg = true; + alltypes.has_opt_fbytes = true; + memcpy(alltypes.opt_fbytes, "3059", 4); + + alltypes.which_oneof = AllTypes_oneof_msg1_tag; + strcpy(alltypes.oneof.oneof_msg1.substuff1, "4059"); + alltypes.oneof.oneof_msg1.substuff2 = 4059; + } + + alltypes.end = 1099; + + { + uint8_t buffer[AllTypes_size]; + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + + /* Now encode it and check if we succeeded. */ + if (pb_encode(&stream, AllTypes_fields, &alltypes)) + { + SET_BINARY_MODE(stdout); + fwrite(buffer, 1, stream.bytes_written, stdout); + return 0; /* Success */ + } + else + { + fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream)); + return 1; /* Failure */ + } + } +} diff --git a/tests/without_64bit/no_64bit_syshdr.h b/tests/without_64bit/no_64bit_syshdr.h new file mode 100644 index 0000000..50c0717 --- /dev/null +++ b/tests/without_64bit/no_64bit_syshdr.h @@ -0,0 +1,17 @@ +/* This wrapper undefines (u)int64_t */ + +#define uint64_t disabled_uint64_t +#define int64_t disabled_int64_t + +#ifdef PB_OLD_SYSHDR +#include PB_OLD_SYSHDR +#else +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#endif + +#undef uint64_t +#undef int64_t + |