diff --git a/docs/Makefile b/docs/Makefile index 3c95399..cfd84ac 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -6,3 +6,4 @@ all: index.html concepts.html reference.html \ %.html: %.rst rst2html --stylesheet=lsr.css --link-stylesheet $< $@ + sed -i 's!!\n!' $@ diff --git a/docs/logo/logo.png b/docs/logo/logo.png new file mode 100644 index 0000000..0d9534f Binary files /dev/null and b/docs/logo/logo.png differ diff --git a/docs/logo/logo.svg b/docs/logo/logo.svg new file mode 100644 index 0000000..91ab28b --- /dev/null +++ b/docs/logo/logo.svg @@ -0,0 +1,1470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Pb + Pb + + + + + + + + + + + + + + + + + + nano + nano + + + + + diff --git a/docs/logo/logo16px.png b/docs/logo/logo16px.png new file mode 100644 index 0000000..8db0e2e Binary files /dev/null and b/docs/logo/logo16px.png differ diff --git a/docs/logo/logo48px.png b/docs/logo/logo48px.png new file mode 100644 index 0000000..b598c01 Binary files /dev/null and b/docs/logo/logo48px.png differ diff --git a/generator/Makefile b/generator/Makefile new file mode 100644 index 0000000..161ef38 --- /dev/null +++ b/generator/Makefile @@ -0,0 +1,2 @@ +nanopb_pb2.py: nanopb.proto + protoc --python_out=. -I /usr/include -I . nanopb.proto diff --git a/pb.h b/pb.h index 71c76f0..b4d5a38 100644 --- a/pb.h +++ b/pb.h @@ -206,4 +206,4 @@ typedef enum { #define PB_LAST_FIELD {0,0,0,0} -#endif \ No newline at end of file +#endif diff --git a/pb_decode.c b/pb_decode.c index 65675d9..a8e97f3 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -561,8 +561,10 @@ bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, v #ifdef __BIG_ENDIAN__ uint8_t bytes[4] = {0}; bool status = pb_read(stream, bytes, 4); - uint8_t bebytes[4] = {bytes[3], bytes[2], bytes[1], bytes[0]}; - memcpy(dest, bebytes, 4); + if (status) { + uint8_t bebytes[4] = {bytes[3], bytes[2], bytes[1], bytes[0]}; + memcpy(dest, bebytes, 4); + } return status; #else return pb_read(stream, (uint8_t*)dest, 4); @@ -574,9 +576,11 @@ bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, v #ifdef __BIG_ENDIAN__ uint8_t bytes[8] = {0}; bool status = pb_read(stream, bytes, 8); - uint8_t bebytes[8] = {bytes[7], bytes[6], bytes[5], bytes[4], - bytes[3], bytes[2], bytes[1], bytes[0]}; - memcpy(dest, bebytes, 8); + if (status) { + uint8_t bebytes[8] = {bytes[7], bytes[6], bytes[5], bytes[4], + bytes[3], bytes[2], bytes[1], bytes[0]}; + memcpy(dest, bebytes, 8); + } return status; #else return pb_read(stream, (uint8_t*)dest, 8); diff --git a/pb_encode.c b/pb_encode.c index 6837f32..291aa30 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -389,6 +389,7 @@ bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field status = pb_encode(&substream, (const pb_message_t*)field->ptr, src); stream->bytes_written += substream.bytes_written; + stream->state = substream.state; if (substream.bytes_written != size) return false; diff --git a/pb_encode.h b/pb_encode.h index f0d0861..0cf9713 100644 --- a/pb_encode.h +++ b/pb_encode.h @@ -69,4 +69,4 @@ bool pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src bool pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); bool pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); -#endif \ No newline at end of file +#endif diff --git a/tests/Makefile b/tests/Makefile index e66d831..4a47626 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -24,7 +24,9 @@ decode_ptr_unittests.o: decode_unittests.c $(DEPS) $(CC) $(CFLAGS) -c -o $@ $< test_decode1: test_decode1.o pb_decode.o person.pb.o +test_decode2: test_decode2.o pb_decode.o person.pb.o test_encode1: test_encode1.o pb_encode.o person.pb.o +test_encode2: test_encode2.o pb_encode.o person.pb.o test_decode_callbacks: test_decode_callbacks.o pb_decode.o callbacks.pb.o test_encode_callbacks: test_encode_callbacks.o pb_encode.o callbacks.pb.o decode_unittests: decode_unittests.o pb_decode.o unittestproto.pb.o @@ -47,7 +49,7 @@ coverage: run_unittests gcov pb_decode.gcda gcov pb_ptr_decode.gcda -run_unittests: decode_unittests decode_ptr_unittests encode_unittests test_encode1 test_decode1 test_encode_callbacks test_decode_callbacks +run_unittests: decode_unittests decode_ptr_unittests encode_unittests test_encode1 test_encode2 test_decode1 test_decode2 test_encode_callbacks test_decode_callbacks rm -f *.gcda ./decode_unittests > /dev/null @@ -56,9 +58,15 @@ run_unittests: decode_unittests decode_ptr_unittests encode_unittests test_encod [ "`./test_encode1 | ./test_decode1`" = \ "`./test_encode1 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ] + + [ "`./test_encode2 | ./test_decode1`" = \ + "`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ] + + [ "`./test_encode2 | ./test_decode2`" = \ + "`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ] [ "`./test_encode_callbacks | ./test_decode_callbacks`" = \ "`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ] -run_fuzztest: test_decode1 - bash -c 'I=1; while cat /dev/urandom | ./test_decode1 > /dev/null; do I=$$(($$I+1)); echo -en "\r$$I"; done' +run_fuzztest: test_decode2 + bash -c 'I=1; while true; do cat /dev/urandom | ./test_decode2 > /dev/null; I=$$(($$I+1)); echo -en "\r$$I"; done' diff --git a/tests/test_decode1.c b/tests/test_decode1.c index edad6ad..83aae4c 100644 --- a/tests/test_decode1.c +++ b/tests/test_decode1.c @@ -23,7 +23,7 @@ bool print_person(pb_istream_t *stream) /* Now the decoding is done, rest is just to print stuff out. */ printf("name: \"%s\"\n", person.name); - printf("id: %d\n", person.id); + printf("id: %ld\n", (long)person.id); if (Person_has(person, email)) printf("email: \"%s\"\n", person.email); @@ -34,19 +34,22 @@ bool print_person(pb_istream_t *stream) printf("phone {\n"); printf(" number: \"%s\"\n", phone->number); - switch (phone->type) + if (Person_PhoneNumber_has(*phone, type)) { - case Person_PhoneType_WORK: - printf(" type: WORK\n"); - break; - - case Person_PhoneType_HOME: - printf(" type: HOME\n"); - break; - - case Person_PhoneType_MOBILE: - printf(" type: MOBILE\n"); - break; + switch (phone->type) + { + case Person_PhoneType_WORK: + printf(" type: WORK\n"); + break; + + case Person_PhoneType_HOME: + printf(" type: HOME\n"); + break; + + case Person_PhoneType_MOBILE: + printf(" type: MOBILE\n"); + break; + } } printf("}\n"); } @@ -54,33 +57,16 @@ bool print_person(pb_istream_t *stream) return true; } -/* This binds the pb_istream_t to stdin */ -bool callback(pb_istream_t *stream, uint8_t *buf, size_t count) -{ - FILE *file = (FILE*)stream->state; - bool status; - - if (buf == NULL) - { - /* Skipping data */ - while (count-- && fgetc(file) != EOF); - return count == 0; - } - - status = (fread(buf, 1, count, file) == count); - - if (feof(file)) - stream->bytes_left = 0; - - return status; -} - int main() { - /* Maximum size is specified to prevent infinite length messages from - * hanging this in the fuzz test. - */ - pb_istream_t stream = {&callback, stdin, 10000}; + /* Read the data into buffer */ + uint8_t buffer[512]; + size_t count = fread(buffer, 1, sizeof(buffer), stdin); + + /* Construct a pb_istream_t for reading from the buffer */ + pb_istream_t stream = pb_istream_from_buffer(buffer, count); + + /* Decode and print out the stuff */ if (!print_person(&stream)) { printf("Parsing failed.\n"); diff --git a/tests/test_decode2.c b/tests/test_decode2.c new file mode 100644 index 0000000..b2e2b68 --- /dev/null +++ b/tests/test_decode2.c @@ -0,0 +1,90 @@ +/* Same as test_decode1 but reads from stdin directly. + */ + +#include +#include +#include "person.pb.h" + +/* This function is called once from main(), it handles + the decoding and printing. + Ugly copy-paste from test_decode1.c. */ +bool print_person(pb_istream_t *stream) +{ + int i; + Person person; + + if (!pb_decode(stream, Person_msg, &person)) + return false; + + /* Now the decoding is done, rest is just to print stuff out. */ + + printf("name: \"%s\"\n", person.name); + printf("id: %ld\n", (long)person.id); + + if (Person_has(person, email)) + printf("email: \"%s\"\n", person.email); + + for (i = 0; i < person.phone_count; i++) + { + Person_PhoneNumber *phone = &person.phone[i]; + printf("phone {\n"); + printf(" number: \"%s\"\n", phone->number); + + if (Person_PhoneNumber_has(*phone, type)) + { + switch (phone->type) + { + case Person_PhoneType_WORK: + printf(" type: WORK\n"); + break; + + case Person_PhoneType_HOME: + printf(" type: HOME\n"); + break; + + case Person_PhoneType_MOBILE: + printf(" type: MOBILE\n"); + break; + } + } + printf("}\n"); + } + + return true; +} + +/* This binds the pb_istream_t to stdin */ +bool callback(pb_istream_t *stream, uint8_t *buf, size_t count) +{ + FILE *file = (FILE*)stream->state; + bool status; + + if (buf == NULL) + { + /* Skipping data */ + while (count-- && fgetc(file) != EOF); + return count == 0; + } + + status = (fread(buf, 1, count, file) == count); + + if (feof(file)) + stream->bytes_left = 0; + + return status; +} + +int main() +{ + /* Maximum size is specified to prevent infinite length messages from + * hanging this in the fuzz test. + */ + pb_istream_t stream = {&callback, stdin, 10000}; + if (!print_person(&stream)) + { + printf("Parsing failed.\n"); + return 1; + } else { + return 0; + } +} diff --git a/tests/test_decode_callbacks.c b/tests/test_decode_callbacks.c index 02c3421..b6073b3 100644 --- a/tests/test_decode_callbacks.c +++ b/tests/test_decode_callbacks.c @@ -30,7 +30,7 @@ bool print_int32(pb_istream_t *stream, const pb_field_t *field, void *arg) if (!pb_decode_varint(stream, &value)) return false; - printf((char*)arg, (int32_t)value); + printf((char*)arg, (long)value); return true; } @@ -40,7 +40,7 @@ bool print_fixed32(pb_istream_t *stream, const pb_field_t *field, void *arg) if (!pb_dec_fixed32(stream, NULL, &value)) return false; - printf((char*)arg, value); + printf((char*)arg, (long)value); return true; } @@ -50,7 +50,7 @@ bool print_fixed64(pb_istream_t *stream, const pb_field_t *field, void *arg) if (!pb_dec_fixed64(stream, NULL, &value)) return false; - printf((char*)arg, value); + printf((char*)arg, (long long)value); return true; } @@ -69,18 +69,18 @@ int main() testmessage.submsg.stringvalue.funcs.decode = &print_string; testmessage.submsg.stringvalue.arg = "submsg {\n stringvalue: \"%s\"\n"; testmessage.submsg.int32value.funcs.decode = &print_int32; - testmessage.submsg.int32value.arg = " int32value: %d\n"; + testmessage.submsg.int32value.arg = " int32value: %ld\n"; testmessage.submsg.fixed32value.funcs.decode = &print_fixed32; - testmessage.submsg.fixed32value.arg = " fixed32value: %d\n"; + testmessage.submsg.fixed32value.arg = " fixed32value: %ld\n"; testmessage.submsg.fixed64value.funcs.decode = &print_fixed64; testmessage.submsg.fixed64value.arg = " fixed64value: %lld\n}\n"; testmessage.stringvalue.funcs.decode = &print_string; testmessage.stringvalue.arg = "stringvalue: \"%s\"\n"; testmessage.int32value.funcs.decode = &print_int32; - testmessage.int32value.arg = "int32value: %d\n"; + testmessage.int32value.arg = "int32value: %ld\n"; testmessage.fixed32value.funcs.decode = &print_fixed32; - testmessage.fixed32value.arg = "fixed32value: %d\n"; + testmessage.fixed32value.arg = "fixed32value: %ld\n"; testmessage.fixed64value.funcs.decode = &print_fixed64; testmessage.fixed64value.arg = "fixed64value: %lld\n"; diff --git a/tests/test_encode1.c b/tests/test_encode1.c index 5c4adf0..039cc6e 100644 --- a/tests/test_encode1.c +++ b/tests/test_encode1.c @@ -1,33 +1,36 @@ /* A very simple encoding test case using person.proto. - * Just puts constant data in the fields and writes the - * data to stdout. + * Just puts constant data in the fields and encodes into + * buffer, which is then written to stdout. */ #include #include #include "person.pb.h" -/* This binds the pb_ostream_t into the stdout stream */ -bool streamcallback(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - FILE *file = (FILE*) stream->state; - return fwrite(buf, 1, count, file) == count; -} - int main() { /* Initialize the structure with constants */ - Person person = {{0}, "Test Person 99", 99, "test@person.com", - 1, {{{0}, "555-12345678", Person_PhoneType_MOBILE}}}; - Person_set(person, email); - Person_PhoneNumber_set(person.phone[0], type); + Person person = {{1 << Person_email_index}, + "Test Person 99", 99, "test@person.com", + 3, {{{1 << Person_PhoneNumber_type_index}, + "555-12345678", Person_PhoneType_MOBILE}, + {{1 << Person_PhoneNumber_type_index}, + "99-2342", 0}, + {{1 << Person_PhoneNumber_type_index}, + "1234-5678", Person_PhoneType_WORK}, + }}; - /* Prepare the stream, output goes directly to stdout */ - pb_ostream_t stream = {&streamcallback, stdout, SIZE_MAX, 0}; + uint8_t buffer[512]; + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); /* Now encode it and check if we succeeded. */ if (pb_encode(&stream, Person_msg, &person)) + { + fwrite(buffer, 1, stream.bytes_written, stdout); return 0; /* Success */ + } else + { return 1; /* Failure */ + } } diff --git a/tests/test_encode2.c b/tests/test_encode2.c new file mode 100644 index 0000000..133bf1c --- /dev/null +++ b/tests/test_encode2.c @@ -0,0 +1,36 @@ +/* Same as test_encode1.c, except writes directly to stdout. + */ + +#include +#include +#include "person.pb.h" + +/* This binds the pb_ostream_t into the stdout stream */ +bool streamcallback(pb_ostream_t *stream, const uint8_t *buf, size_t count) +{ + FILE *file = (FILE*) stream->state; + return fwrite(buf, 1, count, file) == count; +} + +int main() +{ + /* Initialize the structure with constants */ + Person person = {{1 << Person_email_index}, + "Test Person 99", 99, "test@person.com", + 3, {{{1 << Person_PhoneNumber_type_index}, + "555-12345678", Person_PhoneType_MOBILE}, + {{1 << Person_PhoneNumber_type_index}, + "99-2342", 0}, + {{1 << Person_PhoneNumber_type_index}, + "1234-5678", Person_PhoneType_WORK}, + }}; + + /* Prepare the stream, output goes directly to stdout */ + pb_ostream_t stream = {&streamcallback, stdout, SIZE_MAX, 0}; + + /* Now encode it and check if we succeeded. */ + if (pb_encode(&stream, Person_msg, &person)) + return 0; /* Success */ + else + return 1; /* Failure */ +}