aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party
diff options
context:
space:
mode:
Diffstat (limited to 'third_party')
-rw-r--r--third_party/nanopb/AUTHORS24
-rw-r--r--third_party/nanopb/BUILD18
-rw-r--r--third_party/nanopb/CHANGELOG.txt24
-rw-r--r--third_party/nanopb/CONTRIBUTING.md32
-rw-r--r--third_party/nanopb/docs/concepts.rst59
-rw-r--r--third_party/nanopb/docs/index.rst11
-rw-r--r--third_party/nanopb/docs/migration.rst18
-rw-r--r--third_party/nanopb/docs/reference.rst137
-rw-r--r--third_party/nanopb/docs/security.rst7
-rw-r--r--third_party/nanopb/extra/pb_syshdr.h8
-rwxr-xr-xthird_party/nanopb/generator/nanopb_generator.py140
-rw-r--r--third_party/nanopb/generator/proto/nanopb.proto4
-rw-r--r--third_party/nanopb/pb.h88
-rw-r--r--third_party/nanopb/pb_decode.c212
-rw-r--r--third_party/nanopb/pb_decode.h6
-rw-r--r--third_party/nanopb/pb_encode.c140
-rw-r--r--third_party/nanopb/pb_encode.h8
-rw-r--r--third_party/nanopb/tests/anonymous_oneof/SConscript30
-rw-r--r--third_party/nanopb/tests/anonymous_oneof/decode_oneof.c88
-rw-r--r--third_party/nanopb/tests/anonymous_oneof/oneof.proto23
-rw-r--r--third_party/nanopb/tests/fuzztest/fuzztest.c1
-rw-r--r--third_party/nanopb/tests/inline/SConscript16
-rw-r--r--third_party/nanopb/tests/inline/inline.expected3
-rw-r--r--third_party/nanopb/tests/inline/inline.proto17
-rw-r--r--third_party/nanopb/tests/inline/inline_unittests.c73
-rw-r--r--third_party/nanopb/tests/mem_release/mem_release.c2
-rw-r--r--third_party/nanopb/tests/mem_release/mem_release.proto1
-rw-r--r--third_party/nanopb/tests/multiple_files/SConscript5
-rw-r--r--third_party/nanopb/tests/multiple_files/subdir/multifile2.proto25
-rw-r--r--third_party/nanopb/tests/multiple_files/test_multiple_files.c8
-rw-r--r--third_party/nanopb/tests/regression/issue_188/SConscript6
-rw-r--r--third_party/nanopb/tests/regression/issue_188/oneof.proto29
-rw-r--r--third_party/nanopb/tests/regression/issue_195/SConscript10
-rw-r--r--third_party/nanopb/tests/regression/issue_195/test.expected1
-rw-r--r--third_party/nanopb/tests/regression/issue_195/test.proto8
-rw-r--r--third_party/nanopb/tests/regression/issue_203/SConscript9
-rw-r--r--third_party/nanopb/tests/regression/issue_203/file1.proto10
-rw-r--r--third_party/nanopb/tests/regression/issue_203/file2.proto10
-rw-r--r--third_party/nanopb/tests/regression/issue_205/SConscript14
-rw-r--r--third_party/nanopb/tests/regression/issue_205/size_corruption.c12
-rw-r--r--third_party/nanopb/tests/regression/issue_205/size_corruption.proto11
-rw-r--r--third_party/nanopb/tests/site_scons/site_tools/nanopb.py2
m---------third_party/thrift0
43 files changed, 1048 insertions, 302 deletions
diff --git a/third_party/nanopb/AUTHORS b/third_party/nanopb/AUTHORS
new file mode 100644
index 0000000000..a967d3eccc
--- /dev/null
+++ b/third_party/nanopb/AUTHORS
@@ -0,0 +1,24 @@
+Petteri Aimonen <jpa@npb.mail.kapsi.fi>
+Michael Poole <mdpoole@troilus.org>
+Daniel Kan <extremeblue99@gmail.com>
+Stan Hu <stanhu@aclimalabs.com>
+dch <david.hotham@blueyonder.co.uk>
+Steffen Siering <steffen siering gmail com>
+Jens Steinhauser <jens.steinhauser@gmail.com>
+Pavel Ilin <ilin.pa@gmail.com>
+Kent Ryhorchuk <kryhorchuk@xeralux.com>
+Martin Donath <scifish@gmail.com>
+Oliver Lee <oliverzlee@gmail.com>
+Michael Haberler <git@mah.priv.at>
+Nicolas Colomer <ncolomer@viadeoteam.com>
+Ivan Kravets <me@ikravets.com>
+Kyle Manna <kyle@kylemanna.com>
+Benjamin Kamath <ben.kamath@synapse.com>
+Andrew Ruder <andrew.ruder@elecsyscorp.com>
+Kenshi Kawaguchi <kenshi@recurse.ca>
+isotes <isotes@gmail.com>
+Maxim Khitrov <max@mxcrypt.com>
+Yaniv Mordekhay <yanivmo@users.noreply.github.com>
+Ming Zhao <mzhao@luminatewireless.com>
+Google, Inc.
+Tom Roeder <tmroeder@google.com>
diff --git a/third_party/nanopb/BUILD b/third_party/nanopb/BUILD
new file mode 100644
index 0000000000..570988435f
--- /dev/null
+++ b/third_party/nanopb/BUILD
@@ -0,0 +1,18 @@
+licenses(["notice"])
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "nanopb",
+ visibility = ["//visibility:public"],
+ hdrs = [
+ "pb.h",
+ "pb_common.h",
+ "pb_decode.h",
+ "pb_encode.h",
+ ],
+ srcs = [
+ "pb_common.c",
+ "pb_decode.c",
+ "pb_encode.c",
+ ],
+)
diff --git a/third_party/nanopb/CHANGELOG.txt b/third_party/nanopb/CHANGELOG.txt
index b81b847eac..8437688fc5 100644
--- a/third_party/nanopb/CHANGELOG.txt
+++ b/third_party/nanopb/CHANGELOG.txt
@@ -1,3 +1,27 @@
+nanopb-0.3.6 (2016-06-19)
+ Protect against corrupted _count fields in pb_release (#205)
+ Fix error in STATIC_ASSERT with multiple files (#203)
+ Add -D option to specify output directory (#193)
+ Generate MIN/MAX/ARRAYSIZE defines for enums (#194)
+ Generate comments about uncalculable message sizes (#195)
+ Documentation updates (#196, #201)
+ Improvements to test cases.
+
+nanopb-0.3.5 (2016-02-13)
+ NOTE: If you are using pb_syshdr.h, you will need to add uint_least8_t
+ definition. See docs/migration.rst for details.
+
+ Fix generator crash with Enum inside Oneof (#188)
+ Fix some generator regressions related to .options file path (#172)
+ Add support for platforms without uint8_t (#191)
+ Allow const parameter to pb_istream_from_buffer (#152)
+ Ignore null pointers in pb_release() (#183)
+ Add support for anonymous unions (#184)
+ Add Python3 support to the generator (#169)
+ Add code generator insertion points to generated files (#178)
+ Improvements to CMake script (#181)
+ Improvements to test cases.
+
nanopb-0.3.4 (2015-09-26)
Fix handling of unsigned 8- and 16-bit enums (issue 164)
Fix generator on systems where python = python3. (issue 155)
diff --git a/third_party/nanopb/CONTRIBUTING.md b/third_party/nanopb/CONTRIBUTING.md
new file mode 100644
index 0000000000..4041bc3caf
--- /dev/null
+++ b/third_party/nanopb/CONTRIBUTING.md
@@ -0,0 +1,32 @@
+Contributing to Nanopb development
+==================================
+
+Reporting issues and requesting features
+----------------------------------------
+
+Feel free to report any issues you see or features you would like
+to see in the future to the Github issue tracker. Using the templates
+below is preferred:
+
+* [Report a bug](https://github.com/nanopb/nanopb/issues/new?body=**Steps%20to%20reproduce%20the%20issue**%0a%0a1.%0a2.%0a3.%0a%0a**What%20happens?**%0A%0A**What%20should%20happen?**&labels=Type-Defect)
+* [Request a feature](https://github.com/nanopb/nanopb/issues/new?body=**What%20should%20the%20feature%20do?**%0A%0A**In%20what%20situation%20would%20the%20feature%20be%20useful?**&labels=Type-Enhancement)
+
+Requesting help
+---------------
+
+If there is something strange going on, but you do not know if
+it is actually a bug in nanopb, try asking first on the
+[discussion forum](https://groups.google.com/forum/#!forum/nanopb).
+
+Pull requests
+-------------
+
+Pull requests are welcome!
+
+If it is not obvious from the commit message, please indicate the
+same information as you would for an issue report:
+
+* What functionality it fixes/adds.
+* How can the problem be reproduced / when would the feature be useful.
+
+
diff --git a/third_party/nanopb/docs/concepts.rst b/third_party/nanopb/docs/concepts.rst
index b0fd43aab7..c43d829999 100644
--- a/third_party/nanopb/docs/concepts.rst
+++ b/third_party/nanopb/docs/concepts.rst
@@ -148,6 +148,7 @@ Most Protocol Buffers datatypes have directly corresponding C datatypes, such as
1) Strings, bytes and repeated fields of any type map to callback functions by default.
2) If there is a special option *(nanopb).max_size* specified in the .proto file, string maps to null-terminated char array and bytes map to a structure containing a char array and a size field.
+3) If *(nanopb).type* is set to *FT_INLINE* and *(nanopb).max_size* is also set, then bytes map to an inline byte array of fixed size.
3) If there is a special option *(nanopb).max_count* specified on a repeated field, it maps to an array of whatever type is being repeated. Another field will be created for the actual number of entries stored.
=============================================================================== =======================
@@ -160,9 +161,10 @@ repeated string name = 1 [(nanopb).max_size = 40, (nanopb).max_count = 5];
| char name[5][40];
required bytes data = 1 [(nanopb).max_size = 40]; | typedef struct {
| size_t size;
- | uint8_t bytes[40];
+ | pb_byte_t bytes[40];
| } Person_data_t;
| Person_data_t data;
+required bytes data = 1 [(nanopb).max_size = 40, (nanopb.type) = FT_INLINE]; | pb_byte_t data[40];
=============================================================================== =======================
The maximum lengths are checked in runtime. If string/bytes/array exceeds the allocated length, *pb_decode* will return false.
@@ -255,6 +257,61 @@ generates this field description array for the structure *Person_PhoneNumber*::
PB_LAST_FIELD
};
+Oneof
+=====
+Protocol Buffers supports `oneof`_ sections. Here is an example of ``oneof`` usage::
+
+ message MsgType1 {
+ required int32 value = 1;
+ }
+
+ message MsgType2 {
+ required bool value = 1;
+ }
+
+ message MsgType3 {
+ required int32 value1 = 1;
+ required int32 value2 = 2;
+ }
+
+ message MyMessage {
+ required uint32 uid = 1;
+ required uint32 pid = 2;
+ required uint32 utime = 3;
+
+ oneof payload {
+ MsgType1 msg1 = 4;
+ MsgType2 msg2 = 5;
+ MsgType3 msg3 = 6;
+ }
+ }
+
+Nanopb will generate ``payload`` as a C union and add an additional field ``which_payload``::
+
+ typedef struct _MyMessage {
+ uint32_t uid;
+ uint32_t pid;
+ uint32_t utime;
+ pb_size_t which_payload;
+ union {
+ MsgType1 msg1;
+ MsgType2 msg2;
+ MsgType3 msg3;
+ } payload;
+ /* @@protoc_insertion_point(struct:MyMessage) */
+ } MyMessage;
+
+``which_payload`` indicates which of the ``oneof`` fields is actually set.
+The user is expected to set the filed manually using the correct field tag::
+
+ MyMessage msg = MyMessage_init_zero;
+ msg.payload.msg2.value = true;
+ msg.which_payload = MyMessage_msg2_tag;
+
+Notice that neither ``which_payload`` field nor the unused fileds in ``payload``
+will consume any space in the resulting encoded message.
+
+.. _`oneof`: https://developers.google.com/protocol-buffers/docs/reference/proto2-spec#oneof_and_oneof_field
Extension fields
================
diff --git a/third_party/nanopb/docs/index.rst b/third_party/nanopb/docs/index.rst
index d49abc0708..afc7ee4fbf 100644
--- a/third_party/nanopb/docs/index.rst
+++ b/third_party/nanopb/docs/index.rst
@@ -7,7 +7,7 @@ Nanopb: Protocol Buffers with small code size
Nanopb is an ANSI-C library for encoding and decoding messages in Google's `Protocol Buffers`__ format with minimal requirements for RAM and code space.
It is primarily suitable for 32-bit microcontrollers.
-__ http://code.google.com/apis/protocolbuffers/
+__ https://developers.google.com/protocol-buffers/docs/reference/overview
Overall structure
=================
@@ -23,6 +23,7 @@ So a typical project might include these files:
1) Nanopb runtime library:
- pb.h
+ - pb_common.h and pb_common.c (always needed)
- pb_decode.h and pb_decode.c (needed for decoding messages)
- pb_encode.h and pb_encode.c (needed for encoding messages)
2) Protocol description (you can have many):
@@ -39,9 +40,9 @@ Features and limitations
#) Small code size (2–10 kB depending on processor, plus any message definitions)
#) Small ram usage (typically ~300 bytes, plus any message structs)
#) Allows specifying maximum size for strings and arrays, so that they can be allocated statically.
-#) No malloc needed: everything can be allocated statically or on the stack.
+#) No malloc needed: everything can be allocated statically or on the stack. Optional malloc support available.
#) You can use either encoder or decoder alone to cut the code size in half.
-#) Support for most protobuf features, including: all data types, nested submessages, default values, repeated and optional fields, packed arrays, extension fields.
+#) Support for most protobuf features, including: all data types, nested submessages, default values, repeated and optional fields, oneofs, packed arrays, extension fields.
#) Callback mechanism for handling messages larger than can fit in available RAM.
#) Extensive set of tests.
@@ -53,8 +54,8 @@ Features and limitations
#) Fields in the generated structs are ordered by the tag number, instead of the natural ordering in .proto file.
#) Unknown fields are not preserved when decoding and re-encoding a message.
#) Reflection (runtime introspection) is not supported. E.g. you can't request a field by giving its name in a string.
-#) Numeric arrays are always encoded as packed, even if not marked as packed in .proto. This causes incompatibility with decoders that do not support packed format.
-#) Cyclic references between messages are supported only in callback mode.
+#) Numeric arrays are always encoded as packed, even if not marked as packed in .proto.
+#) Cyclic references between messages are supported only in callback and malloc mode.
Getting started
===============
diff --git a/third_party/nanopb/docs/migration.rst b/third_party/nanopb/docs/migration.rst
index ac92db88d4..cd5911f571 100644
--- a/third_party/nanopb/docs/migration.rst
+++ b/third_party/nanopb/docs/migration.rst
@@ -11,6 +11,24 @@ are included, in order to make it easier to find this document.
.. contents ::
+Nanopb-0.3.5 (2016-02-13)
+=========================
+
+Add support for platforms without uint8_t
+-----------------------------------------
+**Rationale:** Some platforms cannot access 8-bit sized values directly, and
+do not define *uint8_t*. Nanopb previously didn't support these platforms.
+
+**Changes:** References to *uint8_t* were replaced with several alternatives,
+one of them being a new *pb_byte_t* typedef. This in turn uses *uint_least8_t*
+which means the smallest available type.
+
+**Required actions:** If your platform does not have a standards-compliant
+*stdint.h*, it may lack the definition for *[u]int_least8_t*. This must be
+added manually, example can be found in *extra/pb_syshdr.h*.
+
+**Error indications:** Compiler error: "unknown type name 'uint_least8_t'".
+
Nanopb-0.3.2 (2015-01-24)
=========================
diff --git a/third_party/nanopb/docs/reference.rst b/third_party/nanopb/docs/reference.rst
index 296bc78c2a..ef3867a117 100644
--- a/third_party/nanopb/docs/reference.rst
+++ b/third_party/nanopb/docs/reference.rst
@@ -20,10 +20,6 @@ You must have the same settings for the nanopb library and all code that
includes pb.h.
============================ ================================================
-__BIG_ENDIAN__ Set this if your platform stores integers and
- floats in big-endian format. Mixed-endian
- systems (different layout for ints and floats)
- are currently not supported.
PB_NO_PACKED_STRUCTS Disable packed structs. Increases RAM usage but
is necessary on some platforms that do not
support unaligned memory access.
@@ -81,9 +77,11 @@ int_size Override the integer type of a field.
type Type of the generated field. Default value
is *FT_DEFAULT*, which selects automatically.
You can use *FT_CALLBACK*, *FT_POINTER*,
- *FT_STATIC* or *FT_IGNORE* to force a callback
- field, a dynamically allocated field, a static
- field or to completely ignore the field.
+ *FT_STATIC*, *FT_IGNORE*, or *FT_INLINE* to
+ force a callback field, a dynamically
+ allocated field, a static field, to
+ completely ignore the field or to
+ generate an inline bytes field.
long_names Prefix the enum name to the enum value in
definitions, i.e. *EnumName_EnumValue*. Enabled
by default.
@@ -95,6 +93,7 @@ no_unions Generate 'oneof' fields as optional fields
instead of C unions.
msgid Specifies a unique id for this message type.
Can be used by user code as an identifier.
+anonymous_oneof Generate 'oneof' fields as anonymous unions.
============================ ================================================
These options can be defined for the .proto files before they are converted
@@ -202,25 +201,37 @@ The options can be defined in file, message and field scopes::
pb.h
====
+pb_byte_t
+---------
+Type used for storing byte-sized data, such as raw binary input and bytes-type fields. ::
+
+ typedef uint_least8_t pb_byte_t;
+
+For most platforms this is equivalent to `uint8_t`. Some platforms however do not support
+8-bit variables, and on those platforms 16 or 32 bits need to be used for each byte.
+
pb_type_t
---------
-Defines the encoder/decoder behaviour that should be used for a field. ::
+Type used to store the type of each field, to control the encoder/decoder behaviour. ::
- typedef uint8_t pb_type_t;
+ typedef uint_least8_t pb_type_t;
The low-order nibble of the enumeration values defines the function that can be used for encoding and decoding the field data:
-==================== ===== ================================================
-LTYPE identifier Value Storage format
-==================== ===== ================================================
-PB_LTYPE_VARINT 0x00 Integer.
-PB_LTYPE_SVARINT 0x01 Integer, zigzag encoded.
-PB_LTYPE_FIXED32 0x02 32-bit integer or floating point.
-PB_LTYPE_FIXED64 0x03 64-bit integer or floating point.
-PB_LTYPE_BYTES 0x04 Structure with *size_t* field and byte array.
-PB_LTYPE_STRING 0x05 Null-terminated string.
-PB_LTYPE_SUBMESSAGE 0x06 Submessage structure.
-==================== ===== ================================================
+=========================== ===== ================================================
+LTYPE identifier Value Storage format
+=========================== ===== ================================================
+PB_LTYPE_VARINT 0x00 Integer.
+PB_LTYPE_UVARINT 0x01 Unsigned integer.
+PB_LTYPE_SVARINT 0x02 Integer, zigzag encoded.
+PB_LTYPE_FIXED32 0x03 32-bit integer or floating point.
+PB_LTYPE_FIXED64 0x04 64-bit integer or floating point.
+PB_LTYPE_BYTES 0x05 Structure with *size_t* field and byte array.
+PB_LTYPE_STRING 0x06 Null-terminated string.
+PB_LTYPE_SUBMESSAGE 0x07 Submessage structure.
+PB_LTYPE_EXTENSION 0x08 Point to *pb_extension_t*.
+PB_LTYPE_FIXED_LENGTH_BYTES 0x09 Inline *pb_byte_t* array of fixed size.
+=========================== ===== ================================================
The bits 4-5 define whether the field is required, optional or repeated:
@@ -252,14 +263,14 @@ pb_field_t
----------
Describes a single structure field with memory position in relation to others. The descriptions are usually autogenerated. ::
- typedef struct _pb_field_t pb_field_t;
- struct _pb_field_t {
- uint8_t tag;
+ typedef struct pb_field_s pb_field_t;
+ struct pb_field_s {
+ pb_size_t tag;
pb_type_t type;
- uint8_t data_offset;
- int8_t size_offset;
- uint8_t data_size;
- uint8_t array_size;
+ pb_size_t data_offset;
+ pb_ssize_t size_offset;
+ pb_size_t data_size;
+ pb_size_t array_size;
const void *ptr;
} pb_packed;
@@ -278,8 +289,8 @@ pb_bytes_array_t
An byte array with a field for storing the length::
typedef struct {
- size_t size;
- uint8_t bytes[1];
+ pb_size_t size;
+ pb_byte_t bytes[1];
} pb_bytes_array_t;
In an actual array, the length of *bytes* may be different.
@@ -343,12 +354,14 @@ Ties together the extension field type and the storage for the field value::
const pb_extension_type_t *type;
void *dest;
pb_extension_t *next;
+ bool found;
} pb_extension_t;
:type: Pointer to the structure that defines the callback functions.
:dest: Pointer to the variable that stores the field value
(as used by the default extension callback functions.)
:next: Pointer to the next extension handler, or *NULL*.
+:found: Decoder sets this to true if the extension was found.
PB_GET_ERROR
------------
@@ -392,7 +405,7 @@ pb_ostream_from_buffer
----------------------
Constructs an output stream for writing into a memory buffer. This is just a helper function, it doesn't do anything you couldn't do yourself in a callback function. It uses an internal callback that stores the pointer in stream *state* field. ::
- pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize);
+ pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize);
:buf: Memory buffer to write into.
:bufsize: Maximum number of bytes to write.
@@ -404,7 +417,7 @@ pb_write
--------
Writes data to an output stream. Always use this function, instead of trying to call stream callback manually. ::
- bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
+ bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
:stream: Output stream to write to.
:buf: Pointer to buffer with the data to be written.
@@ -445,11 +458,22 @@ This function does this, and it is compatible with *parseDelimitedFrom* in Googl
Writing packed arrays is a little bit more involved: you need to use `pb_encode_tag` and specify `PB_WT_STRING` as the wire type. Then you need to know exactly how much data you are going to write, and use `pb_encode_varint`_ to write out the number of bytes before writing the actual data. Substreams can be used to determine the number of bytes beforehand; see `pb_encode_submessage`_ source code for an example.
+pb_get_encoded_size
+-------------------
+Calculates the length of the encoded message. ::
+
+ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
+
+:size: Calculated size of the encoded message.
+:fields: A field description array, usually autogenerated.
+:src_struct: Pointer to the data that will be serialized.
+:returns: True on success, false on detectable errors in field description or if a field encoder returns false.
+
pb_encode_tag
-------------
Starts a field in the Protocol Buffers binary format: encodes the field number and the wire type of the data. ::
- bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, int field_number);
+ bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
:stream: Output stream to write to. 1-5 bytes will be written.
:wiretype: PB_WT_VARINT, PB_WT_64BIT, PB_WT_STRING or PB_WT_32BIT
@@ -470,14 +494,14 @@ This function only considers the LTYPE of the field. You can use it from your fi
Wire type mapping is as follows:
-========================= ============
-LTYPEs Wire type
-========================= ============
-VARINT, SVARINT PB_WT_VARINT
-FIXED64 PB_WT_64BIT
-STRING, BYTES, SUBMESSAGE PB_WT_STRING
-FIXED32 PB_WT_32BIT
-========================= ============
+============================================= ============
+LTYPEs Wire type
+============================================= ============
+VARINT, UVARINT, SVARINT PB_WT_VARINT
+FIXED64 PB_WT_64BIT
+STRING, BYTES, SUBMESSAGE, FIXED_LENGTH_BYTES PB_WT_STRING
+FIXED32 PB_WT_32BIT
+============================================= ============
pb_encode_varint
----------------
@@ -503,7 +527,7 @@ pb_encode_string
----------------
Writes the length of a string as varint and then contents of the string. Works for fields of type `bytes` and `string`::
- bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size);
+ bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
:stream: Output stream to write to.
:buffer: Pointer to string data.
@@ -563,7 +587,7 @@ pb_istream_from_buffer
----------------------
Helper function for creating an input stream that reads data from a memory buffer. ::
- pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize);
+ pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize);
:buf: Pointer to byte array to read from.
:bufsize: Size of the byte array.
@@ -573,7 +597,7 @@ pb_read
-------
Read data from input stream. Always use this function, don't try to call the stream callback directly. ::
- bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count);
+ bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
:stream: Input stream to read from.
:buf: Buffer to store the data to, or NULL to just read data without storing it anywhere.
@@ -632,39 +656,21 @@ This function is compatible with *writeDelimitedTo* in the Google's Protocol Buf
pb_release
----------
-Releases any dynamically allocated fields.
+Releases any dynamically allocated fields::
void pb_release(const pb_field_t fields[], void *dest_struct);
:fields: A field description array. Usually autogenerated.
-:dest_struct: Pointer to structure where data will be stored.
+:dest_struct: Pointer to structure where data is stored. If NULL, function does nothing.
This function is only available if *PB_ENABLE_MALLOC* is defined. It will release any
pointer type fields in the structure and set the pointers to NULL.
-pb_skip_varint
---------------
-Skip a varint_ encoded integer without decoding it. ::
-
- bool pb_skip_varint(pb_istream_t *stream);
-
-:stream: Input stream to read from. Will read 1 byte at a time until the MSB is clear.
-:returns: True on success, false on IO error.
-
-pb_skip_string
---------------
-Skip a varint-length-prefixed string. This means skipping a value with wire type PB_WT_STRING. ::
-
- bool pb_skip_string(pb_istream_t *stream);
-
-:stream: Input stream to read from.
-:returns: True on success, false on IO error or length exceeding uint32_t.
-
pb_decode_tag
-------------
Decode the tag that comes before field in the protobuf encoding::
- bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, int *tag, bool *eof);
+ bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof);
:stream: Input stream to read from.
:wire_type: Pointer to variable where to store the wire type of the field.
@@ -731,10 +737,9 @@ pb_decode_fixed64
-----------------
Decode a *fixed64*, *sfixed64* or *double* value. ::
- bool pb_dec_fixed(pb_istream_t *stream, const pb_field_t *field, void *dest);
+ bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
:stream: Input stream to read from. 8 bytes will be read.
-:field: Not used.
:dest: Pointer to destination *int64_t*, *uint64_t* or *double*.
:returns: True on success, false on IO errors.
diff --git a/third_party/nanopb/docs/security.rst b/third_party/nanopb/docs/security.rst
index 2d0affc51a..d85461229d 100644
--- a/third_party/nanopb/docs/security.rst
+++ b/third_party/nanopb/docs/security.rst
@@ -38,8 +38,11 @@ these will cause "garbage in, garbage out" behaviour. It will not cause
buffer overflows, information disclosure or other security problems:
1. All data read from *pb_istream_t*.
-2. All fields in message structures, except callbacks, pointers and extensions.
- (Beginning with nanopb-0.2.4, in earlier versions the field sizes are partially unchecked.)
+2. All fields in message structures, except:
+
+ - callbacks (*pb_callback_t* structures)
+ - pointer fields (malloc support) and *_count* fields for pointers
+ - extensions (*pb_extension_t* structures)
Invariants
==========
diff --git a/third_party/nanopb/extra/pb_syshdr.h b/third_party/nanopb/extra/pb_syshdr.h
index 1ff48230a2..55d06a3acc 100644
--- a/third_party/nanopb/extra/pb_syshdr.h
+++ b/third_party/nanopb/extra/pb_syshdr.h
@@ -24,6 +24,14 @@ typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
+
+/* These are ok for most platforms, unless uint8_t is actually not available,
+ * in which case you should give the smallest available type. */
+typedef int8_t int_least8_t;
+typedef uint8_t uint_least8_t;
+typedef uint8_t uint_fast8_t;
+typedef int16_t int_least16_t;
+typedef uint16_t uint_least16_t;
#endif
/* stddef.h subset */
diff --git a/third_party/nanopb/generator/nanopb_generator.py b/third_party/nanopb/generator/nanopb_generator.py
index 2dad4ec1cf..973c7610fb 100755
--- a/third_party/nanopb/generator/nanopb_generator.py
+++ b/third_party/nanopb/generator/nanopb_generator.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
-nanopb_version = "nanopb-0.3.5-dev"
+nanopb_version = "nanopb-0.3.7-dev"
import sys
import re
@@ -125,11 +125,15 @@ class EncodedSize:
'''Class used to represent the encoded size of a field or a message.
Consists of a combination of symbolic sizes and integer sizes.'''
def __init__(self, value = 0, symbols = []):
- if isinstance(value, strtypes + (Names,)):
- symbols = [str(value)]
- value = 0
- self.value = value
- self.symbols = symbols
+ if isinstance(value, EncodedSize):
+ self.value = value.value
+ self.symbols = value.symbols
+ elif isinstance(value, strtypes + (Names,)):
+ self.symbols = [str(value)]
+ self.value = 0
+ else:
+ self.value = value
+ self.symbols = symbols
def __add__(self, other):
if isinstance(other, int):
@@ -193,6 +197,10 @@ class Enum:
result += ' %s;' % self.names
+ result += '\n#define _%s_MIN %s' % (self.names, self.values[0][0])
+ result += '\n#define _%s_MAX %s' % (self.names, self.values[-1][0])
+ result += '\n#define _%s_ARRAYSIZE ((%s)(%s+1))' % (self.names, self.names, self.values[-1][0])
+
if not self.options.long_names:
# Define the long names always so that enum value references
# from other files work properly.
@@ -209,7 +217,7 @@ class FieldMaxSize:
self.worst = worst
self.worst_field = field_name
- self.checks = checks
+ self.checks = list(checks)
def extend(self, extend, field_name = None):
self.worst = max(self.worst, extend.worst)
@@ -233,6 +241,11 @@ class Field:
self.enc_size = None
self.ctype = None
+ self.inline = None
+ if field_options.type == nanopb_pb2.FT_INLINE:
+ field_options.type = nanopb_pb2.FT_STATIC
+ self.inline = nanopb_pb2.FT_INLINE
+
# Parse field options
if field_options.HasField("max_size"):
self.max_size = field_options.max_size
@@ -311,7 +324,12 @@ class Field:
elif desc.type == FieldD.TYPE_BYTES:
self.pbtype = 'BYTES'
if self.allocation == 'STATIC':
- self.ctype = self.struct_name + self.name + 't'
+ # Inline STATIC for BYTES is like STATIC for STRING.
+ if self.inline:
+ self.ctype = 'pb_byte_t'
+ self.array_decl += '[%d]' % self.max_size
+ else:
+ self.ctype = self.struct_name + self.name + 't'
self.enc_size = varint_max_size(self.max_size) + self.max_size
elif self.allocation == 'POINTER':
self.ctype = 'pb_bytes_array_t'
@@ -351,7 +369,7 @@ class Field:
def types(self):
'''Return definitions for any special types this field might need.'''
- if self.pbtype == 'BYTES' and self.allocation == 'STATIC':
+ if self.pbtype == 'BYTES' and self.allocation == 'STATIC' and not self.inline:
result = 'typedef PB_BYTES_ARRAY_T(%d) %s;\n' % (self.max_size, self.ctype)
else:
result = ''
@@ -380,7 +398,10 @@ class Field:
if self.pbtype == 'STRING':
inner_init = '""'
elif self.pbtype == 'BYTES':
- inner_init = '{0, {0}}'
+ if self.inline:
+ inner_init = '{0}'
+ else:
+ inner_init = '{0, {0}}'
elif self.pbtype in ('ENUM', 'UENUM'):
inner_init = '(%s)0' % self.ctype
else:
@@ -392,9 +413,15 @@ class Field:
elif self.pbtype == 'BYTES':
data = ['0x%02x' % ord(c) for c in self.default]
if len(data) == 0:
- inner_init = '{0, {0}}'
+ if self.inline:
+ inner_init = '{0}'
+ else:
+ inner_init = '{0, {0}}'
else:
- inner_init = '{%d, {%s}}' % (len(data), ','.join(data))
+ if self.inline:
+ inner_init = '{%s}' % ','.join(data)
+ else:
+ inner_init = '{%d, {%s}}' % (len(data), ','.join(data))
elif self.pbtype in ['FIXED32', 'UINT32']:
inner_init = str(self.default) + 'u'
elif self.pbtype in ['FIXED64', 'UINT64']:
@@ -446,6 +473,8 @@ class Field:
elif self.pbtype == 'BYTES':
if self.allocation != 'STATIC':
return None # Not implemented
+ if self.inline:
+ array_decl = '[%d]' % self.max_size
if declaration_only:
return 'extern const %s %s_default%s;' % (ctype, self.struct_name + self.name, array_decl)
@@ -463,14 +492,17 @@ class Field:
'''
if self.rules == 'ONEOF':
- result = ' PB_ONEOF_FIELD(%s, ' % self.union_name
+ if self.anonymous:
+ result = ' PB_ANONYMOUS_ONEOF_FIELD(%s, ' % self.union_name
+ else:
+ result = ' PB_ONEOF_FIELD(%s, ' % self.union_name
else:
result = ' PB_FIELD('
result += '%3d, ' % self.tag
result += '%-8s, ' % self.pbtype
result += '%s, ' % self.rules
- result += '%-8s, ' % self.allocation
+ result += '%-8s, ' % (self.allocation if not self.inline else "INLINE")
result += '%s, ' % ("FIRST" if not prev_field_name else "OTHER")
result += '%s, ' % self.struct_name
result += '%s, ' % self.name
@@ -489,6 +521,9 @@ class Field:
return result
+ def get_last_field_name(self):
+ return self.name
+
def largest_field_value(self):
'''Determine if this field needs 16bit or 32bit pb_field_t structure to compile properly.
Returns numeric value or a C-expression for assert.'''
@@ -497,7 +532,10 @@ class Field:
if self.rules == 'REPEATED' and self.allocation == 'STATIC':
check.append('pb_membersize(%s, %s[0])' % (self.struct_name, self.name))
elif self.rules == 'ONEOF':
- check.append('pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name))
+ if self.anonymous:
+ check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name))
+ else:
+ check.append('pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name))
else:
check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name))
@@ -577,6 +615,7 @@ class ExtensionRange(Field):
self.default = None
self.max_size = 0
self.max_count = 0
+ self.inline = None
def __str__(self):
return ' pb_extension_t *extensions;'
@@ -653,6 +692,8 @@ class OneOf(Field):
self.allocation = 'ONEOF'
self.default = None
self.rules = 'ONEOF'
+ self.anonymous = False
+ self.inline = None
def add_field(self, field):
if field.allocation == 'CALLBACK':
@@ -661,6 +702,7 @@ class OneOf(Field):
field.union_name = self.name
field.rules = 'ONEOF'
+ field.anonymous = self.anonymous
self.fields.append(field)
self.fields.sort(key = lambda f: f.tag)
@@ -674,7 +716,10 @@ class OneOf(Field):
result += ' union {\n'
for f in self.fields:
result += ' ' + str(f).replace('\n', '\n ') + '\n'
- result += ' } ' + self.name + ';'
+ if self.anonymous:
+ result += ' };'
+ else:
+ result += ' } ' + self.name + ';'
return result
def types(self):
@@ -693,12 +738,18 @@ class OneOf(Field):
return None
def tags(self):
- return '\n'.join([f.tags() for f in self.fields])
+ return ''.join([f.tags() for f in self.fields])
def pb_field_t(self, prev_field_name):
result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields])
return result
+ def get_last_field_name(self):
+ if self.anonymous:
+ return self.fields[-1].name
+ else:
+ return self.name + '.' + self.fields[-1].name
+
def largest_field_value(self):
largest = FieldMaxSize()
for f in self.fields:
@@ -706,10 +757,11 @@ class OneOf(Field):
return largest
def encoded_size(self, dependencies):
+ '''Returns the size of the largest oneof field.'''
largest = EncodedSize(0)
for f in self.fields:
- size = f.encoded_size(dependencies)
- if size is None:
+ size = EncodedSize(f.encoded_size(dependencies))
+ if size.value is None:
return None
elif size.symbols:
return None # Cannot resolve maximum of symbols
@@ -742,6 +794,8 @@ class Message:
pass # No union and skip fields also
else:
oneof = OneOf(self.name, f)
+ if oneof_options.anonymous_oneof:
+ oneof.anonymous = True
self.oneofs[i] = oneof
self.fields.append(oneof)
@@ -782,9 +836,10 @@ class Message:
if not self.ordered_fields:
# Empty structs are not allowed in C standard.
# Therefore add a dummy field if an empty message occurs.
- result += ' uint8_t dummy_field;'
+ result += ' char dummy_field;'
result += '\n'.join([str(f) for f in self.ordered_fields])
+ result += '\n/* @@protoc_insertion_point(struct:%s) */' % self.name
result += '\n}'
if self.packed:
@@ -847,10 +902,7 @@ class Message:
for field in self.ordered_fields:
result += field.pb_field_t(prev)
result += ',\n'
- if isinstance(field, OneOf):
- prev = field.name + '.' + field.fields[-1].name
- else:
- prev = field.name
+ prev = field.get_last_field_name()
result += ' PB_LAST_FIELD\n};'
return result
@@ -1016,7 +1068,10 @@ class ProtoFile:
else:
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
- symbol = make_identifier(headername)
+ if self.fdesc.package:
+ symbol = make_identifier(self.fdesc.package + '_' + headername)
+ else:
+ symbol = make_identifier(headername)
yield '#ifndef PB_%s_INCLUDED\n' % symbol
yield '#define PB_%s_INCLUDED\n' % symbol
try:
@@ -1031,6 +1086,8 @@ class ProtoFile:
yield options.genformat % (noext + options.extension + '.h')
yield '\n'
+ yield '/* @@protoc_insertion_point(includes) */\n'
+
yield '#if PB_PROTO_HEADER_VERSION != 30\n'
yield '#error Regenerate this file with the current version of nanopb generator.\n'
yield '#endif\n'
@@ -1088,9 +1145,11 @@ class ProtoFile:
yield '/* Maximum encoded size of messages (where known) */\n'
for msg in self.messages:
msize = msg.encoded_size(self.dependencies)
+ identifier = '%s_size' % msg.name
if msize is not None:
- identifier = '%s_size' % msg.name
yield '#define %-40s %s\n' % (identifier, msize)
+ else:
+ yield '/* %s depends on runtime parameters */\n' % identifier
yield '\n'
yield '/* Message IDs (where set with "msgid" option) */\n'
@@ -1125,6 +1184,7 @@ class ProtoFile:
yield '#endif\n'
# End of header
+ yield '/* @@protoc_insertion_point(eof) */\n'
yield '\n#endif\n'
def generate_source(self, headername, options):
@@ -1137,6 +1197,7 @@ class ProtoFile:
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
yield options.genformat % (headername)
yield '\n'
+ yield '/* @@protoc_insertion_point(includes) */\n'
yield '#if PB_PROTO_HEADER_VERSION != 30\n'
yield '#error Regenerate this file with the current version of nanopb generator.\n'
@@ -1229,6 +1290,7 @@ class ProtoFile:
yield 'PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n'
yield '\n'
+ yield '/* @@protoc_insertion_point(eof) */\n'
# ---------------------------------------------------------------------------
# Options parsing for the .proto files
@@ -1333,6 +1395,9 @@ optparser.add_option("-f", "--options-file", dest="options_file", metavar="FILE"
optparser.add_option("-I", "--options-path", dest="options_path", metavar="DIR",
action="append", default = [],
help="Search for .options files additionally in this path")
+optparser.add_option("-D", "--output-dir", dest="output_dir",
+ metavar="OUTPUTDIR", default=None,
+ help="Output directory of .pb.h and .pb.c files")
optparser.add_option("-Q", "--generated-include-format", dest="genformat",
metavar="FORMAT", default='#include "%s"\n',
help="Set format string to use for including other .pb.h files. [default: %default]")
@@ -1449,17 +1514,29 @@ def main_cli():
if options.quiet:
options.verbose = False
- Globals.verbose_options = options.verbose
+ if options.output_dir and not os.path.exists(options.output_dir):
+ optparser.print_help()
+ sys.stderr.write("\noutput_dir does not exist: %s\n" % options.output_dir)
+ sys.exit(1)
+
+ Globals.verbose_options = options.verbose
for filename in filenames:
results = process_file(filename, None, options)
+ base_dir = options.output_dir or ''
+ to_write = [
+ (os.path.join(base_dir, results['headername']), results['headerdata']),
+ (os.path.join(base_dir, results['sourcename']), results['sourcedata']),
+ ]
+
if not options.quiet:
- sys.stderr.write("Writing to " + results['headername'] + " and "
- + results['sourcename'] + "\n")
+ paths = " and ".join([x[0] for x in to_write])
+ sys.stderr.write("Writing to %s\n" % paths)
- open(results['headername'], 'w').write(results['headerdata'])
- open(results['sourcename'], 'w').write(results['sourcedata'])
+ for path, data in to_write:
+ with open(path, 'w') as f:
+ f.write(data)
def main_plugin():
'''Main function when invoked as a protoc plugin.'''
@@ -1523,4 +1600,3 @@ if __name__ == '__main__':
main_plugin()
else:
main_cli()
-
diff --git a/third_party/nanopb/generator/proto/nanopb.proto b/third_party/nanopb/generator/proto/nanopb.proto
index b8671bbdc9..8aab19a1b5 100644
--- a/third_party/nanopb/generator/proto/nanopb.proto
+++ b/third_party/nanopb/generator/proto/nanopb.proto
@@ -16,6 +16,7 @@ enum FieldType {
FT_POINTER = 4; // Always generate a dynamically allocated field.
FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
FT_IGNORE = 3; // Ignore the field completely.
+ FT_INLINE = 5; // Always generate an inline array of fixed size.
}
enum IntSize {
@@ -62,6 +63,9 @@ message NanoPBOptions {
// integer type tag for a message
optional uint32 msgid = 9;
+
+ // decode oneof as anonymous union
+ optional bool anonymous_oneof = 11 [default = false];
}
// Extensions to protoc 'Descriptor' type in order to define options
diff --git a/third_party/nanopb/pb.h b/third_party/nanopb/pb.h
index 98613a06ac..4576f79abc 100644
--- a/third_party/nanopb/pb.h
+++ b/third_party/nanopb/pb.h
@@ -13,10 +13,6 @@
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 1 */
-/* Define this if your CPU architecture is big endian, i.e. it
- * stores the most-significant byte first. */
-/* #define __BIG_ENDIAN__ 1 */
-
/* Define this if your CPU / compiler combination does not support
* unaligned memory access to packed structures. */
/* #define PB_NO_PACKED_STRUCTS 1 */
@@ -50,12 +46,12 @@
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
-#define NANOPB_VERSION nanopb-0.3.5-dev
+#define NANOPB_VERSION nanopb-0.3.7-dev
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
* - strlen, memcpy, memset functions
- * - [u]int8_t, [u]int16_t, [u]int32_t, [u]int64_t
+ * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t
* - size_t
* - bool
*
@@ -144,7 +140,7 @@
* Most-significant 4 bits specify repeated/required/packed etc.
*/
-typedef uint8_t pb_type_t;
+typedef uint_least8_t pb_type_t;
/**** Field data types ****/
@@ -174,8 +170,14 @@ typedef uint8_t pb_type_t;
* The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x08
+/* Byte array with inline, pre-allocated byffer.
+ * data_size is the length of the inline, allocated buffer.
+ * This differs from PB_LTYPE_BYTES by defining the element as
+ * pb_byte_t[data_size] rather than pb_bytes_array_t. */
+#define PB_LTYPE_FIXED_LENGTH_BYTES 0x09
+
/* Number of declared LTYPES */
-#define PB_LTYPES_COUNT 9
+#define PB_LTYPES_COUNT 0x0A
#define PB_LTYPE_MASK 0x0F
/**** Field repetition rules ****/
@@ -201,18 +203,22 @@ typedef uint8_t pb_type_t;
* and array counts.
*/
#if defined(PB_FIELD_32BIT)
-#define PB_SIZE_MAX ((uint32_t)-1)
typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t;
#elif defined(PB_FIELD_16BIT)
-#define PB_SIZE_MAX ((uint16_t)-1)
- typedef uint16_t pb_size_t;
- typedef int16_t pb_ssize_t;
+ typedef uint_least16_t pb_size_t;
+ typedef int_least16_t pb_ssize_t;
#else
-#define PB_SIZE_MAX ((uint8_t)-1)
- typedef uint8_t pb_size_t;
- typedef int8_t pb_ssize_t;
+ typedef uint_least8_t pb_size_t;
+ typedef int_least8_t pb_ssize_t;
#endif
+#define PB_SIZE_MAX ((pb_size_t)-1)
+
+/* Data type for storing encoded data and other byte streams.
+ * This typedef exists to support platforms where uint8_t does not exist.
+ * You can regard it as equivalent on uint8_t on other platforms.
+ */
+typedef uint_least8_t pb_byte_t;
/* This structure is used in auto-generated constants
* to specify struct fields.
@@ -240,30 +246,24 @@ struct pb_field_s {
PB_PACKED_STRUCT_END
/* Make sure that the standard integer types are of the expected sizes.
- * All kinds of things may break otherwise.. atleast all fixed* types.
+ * Otherwise fixed32/fixed64 fields can break.
*
* If you get errors here, it probably means that your stdint.h is not
* correct for your platform.
*/
-PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
+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)
/* This structure is used for 'bytes' arrays.
* It has the number of bytes in the beginning, and after that an array.
* Note that actual structs used will have a different length of bytes array.
*/
-#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; uint8_t bytes[n]; }
+#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; }
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
struct pb_bytes_array_s {
pb_size_t size;
- uint8_t bytes[1];
+ pb_byte_t bytes[1];
};
typedef struct pb_bytes_array_s pb_bytes_array_t;
@@ -421,6 +421,19 @@ struct pb_extension_s {
pb_membersize(st, m[0]), \
pb_arraysize(st, m), ptr}
+#define PB_REQUIRED_INLINE(tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | PB_LTYPE_FIXED_LENGTH_BYTES, \
+ fd, 0, pb_membersize(st, m), 0, ptr}
+
+/* Optional fields add the delta to the has_ variable. */
+#define PB_OPTIONAL_INLINE(tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED_LENGTH_BYTES, \
+ fd, \
+ pb_delta(st, has_ ## m, m), \
+ pb_membersize(st, m), 0, ptr}
+
+/* INLINE does not support REPEATED fields. */
+
/* Allocated fields carry the size of the actual data, not the pointer */
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
@@ -460,6 +473,8 @@ struct pb_extension_s {
#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr)
+/* INLINE does not support OPTEXT. */
+
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr)
@@ -491,7 +506,7 @@ struct pb_extension_s {
* FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
* SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
* - Field rules: REQUIRED, OPTIONAL or REPEATED
- * - Allocation: STATIC or CALLBACK
+ * - Allocation: STATIC, INLINE, or CALLBACK
* - Placement: FIRST or OTHER, depending on if this is the first field in structure.
* - Message name
* - Field name
@@ -517,11 +532,28 @@ struct pb_extension_s {
fd, pb_delta(st, which_ ## u, u.m), \
pb_membersize(st, u.m[0]), 0, ptr}
+/* INLINE does not support ONEOF. */
+
#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
- PB_ ## rules ## _ ## allocation(union_name, tag, message, field, \
+ PB_ONEOF_ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
+#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
+ fd, pb_delta(st, which_ ## u, m), \
+ pb_membersize(st, m), 0, ptr}
+
+#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
+ fd, pb_delta(st, which_ ## u, m), \
+ pb_membersize(st, m[0]), 0, ptr}
+
+#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
+ PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \
+ PB_DATAOFFSET_ ## placement(message, field, prevfield), \
+ PB_LTYPE_MAP_ ## type, ptr)
+
/* These macros are used for giving out error messages.
* They are mostly a debugging aid; the main error information
* is the true/false return value from functions.
diff --git a/third_party/nanopb/pb_decode.c b/third_party/nanopb/pb_decode.c
index 5cdcbcfb10..7a4e29a8fd 100644
--- a/third_party/nanopb/pb_decode.c
+++ b/third_party/nanopb/pb_decode.c
@@ -23,9 +23,9 @@
typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn;
-static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count);
+static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
-static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size);
+static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
@@ -65,17 +65,18 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
&pb_dec_bytes,
&pb_dec_string,
&pb_dec_submessage,
- NULL /* extensions */
+ NULL, /* extensions */
+ &pb_dec_bytes /* PB_LTYPE_FIXED_LENGTH_BYTES */
};
/*******************************
* pb_istream_t implementation *
*******************************/
-static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
+static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
- uint8_t *source = (uint8_t*)stream->state;
- stream->state = source + count;
+ const pb_byte_t *source = (const pb_byte_t*)stream->state;
+ stream->state = (pb_byte_t*)stream->state + count;
if (buf != NULL)
{
@@ -86,13 +87,13 @@ static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t coun
return true;
}
-bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
+bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
#ifndef PB_BUFFER_ONLY
if (buf == NULL && stream->callback != buf_read)
{
/* Skip input bytes */
- uint8_t tmp[16];
+ pb_byte_t tmp[16];
while (count > 16)
{
if (!pb_read(stream, tmp, 16))
@@ -122,7 +123,7 @@ bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
/* Read a single byte from input stream. buf may not be NULL.
* This is an optimization for the varint decoding. */
-static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf)
+static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf)
{
if (stream->bytes_left == 0)
PB_RETURN_ERROR(stream, "end-of-stream");
@@ -131,8 +132,8 @@ static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf)
if (!stream->callback(stream, buf, 1))
PB_RETURN_ERROR(stream, "io error");
#else
- *buf = *(uint8_t*)stream->state;
- stream->state = (uint8_t*)stream->state + 1;
+ *buf = *(const pb_byte_t*)stream->state;
+ stream->state = (pb_byte_t*)stream->state + 1;
#endif
stream->bytes_left--;
@@ -140,15 +141,23 @@ static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf)
return true;
}
-pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
+pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
{
pb_istream_t stream;
+ /* Cast away the const from buf without a compiler error. We are
+ * careful to use it only in a const manner in the callbacks.
+ */
+ union {
+ void *state;
+ const void *c_state;
+ } state;
#ifdef PB_BUFFER_ONLY
stream.callback = NULL;
#else
stream.callback = &buf_read;
#endif
- stream.state = buf;
+ state.c_state = buf;
+ stream.state = state.state;
stream.bytes_left = bufsize;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
@@ -162,7 +171,7 @@ pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
{
- uint8_t byte;
+ pb_byte_t byte;
uint32_t result;
if (!pb_readbyte(stream, &byte))
@@ -176,7 +185,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
else
{
/* Multibyte case */
- uint8_t bitpos = 7;
+ uint_fast8_t bitpos = 7;
result = byte & 0x7F;
do
@@ -188,7 +197,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
return false;
result |= (uint32_t)(byte & 0x7F) << bitpos;
- bitpos = (uint8_t)(bitpos + 7);
+ bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
}
@@ -198,8 +207,8 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
{
- uint8_t byte;
- uint8_t bitpos = 0;
+ pb_byte_t byte;
+ uint_fast8_t bitpos = 0;
uint64_t result = 0;
do
@@ -211,7 +220,7 @@ bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
return false;
result |= (uint64_t)(byte & 0x7F) << bitpos;
- bitpos = (uint8_t)(bitpos + 7);
+ bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
*dest = result;
@@ -220,7 +229,7 @@ bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
bool checkreturn pb_skip_varint(pb_istream_t *stream)
{
- uint8_t byte;
+ pb_byte_t byte;
do
{
if (!pb_read(stream, &byte, 1))
@@ -279,7 +288,7 @@ bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type)
/* Read a raw value to buffer, for the purpose of passing it to callback as
* a substream. Size is maximum size on call, and actual size on return.
*/
-static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size)
+static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size)
{
size_t max_size = *size;
switch (wire_type)
@@ -367,7 +376,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
while (substream.bytes_left > 0 && *size < iter->pos->array_size)
{
- void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
+ void *pItem = (char*)iter->pData + iter->pos->data_size * (*size);
if (!func(&substream, iter->pos, pItem))
{
status = false;
@@ -386,7 +395,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
{
/* Repeated field */
pb_size_t *size = (pb_size_t*)iter->pSize;
- void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
+ void *pItem = (char*)iter->pData + iter->pos->data_size * (*size);
if (*size >= iter->pos->array_size)
PB_RETURN_ERROR(stream, "array overflow");
@@ -540,7 +549,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
}
/* Decode the array entry */
- pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size);
+ pItem = *(char**)iter->pData + iter->pos->data_size * (*size);
initialize_pointer_field(pItem, iter);
if (!func(&substream, iter->pos, pItem))
{
@@ -576,7 +585,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
return false;
- pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1);
+ pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1);
initialize_pointer_field(pItem, iter);
return func(stream, iter->pos, pItem);
}
@@ -623,7 +632,7 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type
* which in turn allows to use same callback for packed and
* not-packed fields. */
pb_istream_t substream;
- uint8_t buffer[10];
+ pb_byte_t buffer[10];
size_t size = sizeof(buffer);
if (!read_raw_value(stream, wire_type, buffer, &size))
@@ -830,7 +839,8 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str
bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
- uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0};
+ const uint32_t allbits = ~(uint32_t)0;
uint32_t extension_range_start = 0;
pb_field_iter_t iter;
@@ -886,8 +896,8 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
{
- uint8_t tmp = (uint8_t)(1 << (iter.required_field_index & 7));
- fields_seen[iter.required_field_index >> 3] |= tmp;
+ uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31));
+ fields_seen[iter.required_field_index >> 5] |= tmp;
}
if (!decode_field(stream, wire_type, &iter))
@@ -912,16 +922,19 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
req_field_count++;
- /* Check the whole bytes */
- for (i = 0; i < (req_field_count >> 3); i++)
+ if (req_field_count > 0)
{
- if (fields_seen[i] != 0xFF)
+ /* Check the whole words */
+ for (i = 0; i < (req_field_count >> 5); i++)
+ {
+ if (fields_seen[i] != allbits)
+ PB_RETURN_ERROR(stream, "missing required field");
+ }
+
+ /* Check the remaining bits */
+ if (fields_seen[req_field_count >> 5] != (allbits >> (32 - (req_field_count & 31))))
PB_RETURN_ERROR(stream, "missing required field");
}
-
- /* Check the remaining bits */
- if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7))))
- PB_RETURN_ERROR(stream, "missing required field");
}
return true;
@@ -1023,6 +1036,12 @@ static void pb_release_single_field(const pb_field_iter_t *iter)
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(pb_size_t*)iter->pSize;
+
+ if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size)
+ {
+ /* Protect against corrupted _count fields */
+ count = iter->pos->array_size;
+ }
}
if (pItem)
@@ -1030,7 +1049,7 @@ static void pb_release_single_field(const pb_field_iter_t *iter)
while (count--)
{
pb_release((const pb_field_t*)iter->pos->ptr, pItem);
- pItem = (uint8_t*)pItem + iter->pos->data_size;
+ pItem = (char*)pItem + iter->pos->data_size;
}
}
}
@@ -1067,6 +1086,9 @@ void pb_release(const pb_field_t fields[], void *dest_struct)
{
pb_field_iter_t iter;
+ if (!dest_struct)
+ return; /* Ignore NULL pointers, similar to free() */
+
if (!pb_field_iter_begin(&iter, fields, dest_struct))
return; /* Empty message type */
@@ -1095,44 +1117,35 @@ bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest)
bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
{
- #ifdef __BIG_ENDIAN__
- uint8_t *bytes = (uint8_t*)dest;
- uint8_t lebytes[4];
-
- if (!pb_read(stream, lebytes, 4))
+ pb_byte_t bytes[4];
+
+ if (!pb_read(stream, bytes, 4))
return false;
- bytes[0] = lebytes[3];
- bytes[1] = lebytes[2];
- bytes[2] = lebytes[1];
- bytes[3] = lebytes[0];
+ *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) |
+ ((uint32_t)bytes[1] << 8) |
+ ((uint32_t)bytes[2] << 16) |
+ ((uint32_t)bytes[3] << 24);
return true;
- #else
- return pb_read(stream, (uint8_t*)dest, 4);
- #endif
}
bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
{
- #ifdef __BIG_ENDIAN__
- uint8_t *bytes = (uint8_t*)dest;
- uint8_t lebytes[8];
-
- if (!pb_read(stream, lebytes, 8))
+ pb_byte_t bytes[8];
+
+ if (!pb_read(stream, bytes, 8))
return false;
- bytes[0] = lebytes[7];
- bytes[1] = lebytes[6];
- bytes[2] = lebytes[5];
- bytes[3] = lebytes[4];
- bytes[4] = lebytes[3];
- bytes[5] = lebytes[2];
- bytes[6] = lebytes[1];
- bytes[7] = lebytes[0];
+ *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) |
+ ((uint64_t)bytes[1] << 8) |
+ ((uint64_t)bytes[2] << 16) |
+ ((uint64_t)bytes[3] << 24) |
+ ((uint64_t)bytes[4] << 32) |
+ ((uint64_t)bytes[5] << 40) |
+ ((uint64_t)bytes[6] << 48) |
+ ((uint64_t)bytes[7] << 56);
+
return true;
- #else
- return pb_read(stream, (uint8_t*)dest, 8);
- #endif
}
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
@@ -1149,19 +1162,22 @@ 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 == 8)
+ if (field->data_size == sizeof(int64_t))
svalue = (int64_t)value;
else
svalue = (int32_t)value;
- switch (field->data_size)
- {
- case 1: clamped = *(int8_t*)dest = (int8_t)svalue; break;
- case 2: clamped = *(int16_t*)dest = (int16_t)svalue; break;
- case 4: clamped = *(int32_t*)dest = (int32_t)svalue; break;
- case 8: clamped = *(int64_t*)dest = svalue; break;
- default: PB_RETURN_ERROR(stream, "invalid data_size");
- }
+ /* Cast to the proper field size, while checking for overflows */
+ if (field->data_size == sizeof(int64_t))
+ clamped = *(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))
+ clamped = *(int_least16_t*)dest = (int_least16_t)svalue;
+ else if (field->data_size == sizeof(int_least8_t))
+ clamped = *(int_least8_t*)dest = (int_least8_t)svalue;
+ else
+ PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != svalue)
PB_RETURN_ERROR(stream, "integer too large");
@@ -1175,14 +1191,17 @@ static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *f
if (!pb_decode_varint(stream, &value))
return false;
- switch (field->data_size)
- {
- case 1: clamped = *(uint8_t*)dest = (uint8_t)value; break;
- case 2: clamped = *(uint16_t*)dest = (uint16_t)value; break;
- case 4: clamped = *(uint32_t*)dest = (uint32_t)value; break;
- case 8: clamped = *(uint64_t*)dest = value; break;
- default: PB_RETURN_ERROR(stream, "invalid data_size");
- }
+ /* Cast to the proper field size, while checking for overflows */
+ if (field->data_size == sizeof(uint64_t))
+ clamped = *(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))
+ clamped = *(uint_least16_t*)dest = (uint_least16_t)value;
+ else if (field->data_size == sizeof(uint_least8_t))
+ clamped = *(uint_least8_t*)dest = (uint_least8_t)value;
+ else
+ PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
@@ -1196,14 +1215,17 @@ static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *f
if (!pb_decode_svarint(stream, &value))
return false;
- switch (field->data_size)
- {
- case 1: clamped = *(int8_t*)dest = (int8_t)value; break;
- case 2: clamped = *(int16_t*)dest = (int16_t)value; break;
- case 4: clamped = *(int32_t*)dest = (int32_t)value; break;
- case 8: clamped = *(int64_t*)dest = value; break;
- default: PB_RETURN_ERROR(stream, "invalid data_size");
- }
+ /* Cast to the proper field size, while checking for overflows */
+ if (field->data_size == sizeof(int64_t))
+ clamped = *(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))
+ clamped = *(int_least16_t*)dest = (int_least16_t)value;
+ else if (field->data_size == sizeof(int_least8_t))
+ clamped = *(int_least8_t*)dest = (int_least8_t)value;
+ else
+ PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
@@ -1251,6 +1273,12 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
}
else
{
+ if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES) {
+ if (size != field->data_size)
+ PB_RETURN_ERROR(stream, "incorrect inline bytes size");
+ return pb_read(stream, (pb_byte_t*)dest, field->data_size);
+ }
+
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "bytes overflow");
bdest = (pb_bytes_array_t*)dest;
@@ -1290,8 +1318,8 @@ static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *fi
PB_RETURN_ERROR(stream, "string overflow");
}
- status = pb_read(stream, (uint8_t*)dest, size);
- *((uint8_t*)dest + size) = 0;
+ status = pb_read(stream, (pb_byte_t*)dest, size);
+ *((pb_byte_t*)dest + size) = 0;
return status;
}
diff --git a/third_party/nanopb/pb_decode.h b/third_party/nanopb/pb_decode.h
index 3d433155b8..1d9bb1945c 100644
--- a/third_party/nanopb/pb_decode.h
+++ b/third_party/nanopb/pb_decode.h
@@ -34,7 +34,7 @@ struct pb_istream_s
*/
int *callback;
#else
- bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
+ bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation */
@@ -103,12 +103,12 @@ void pb_release(const pb_field_t fields[], void *dest_struct);
* Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket.
*/
-pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize);
+pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize);
/* Function to read from a pb_istream_t. You can use this if you need to
* read some custom header data, or to read data in field callbacks.
*/
-bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count);
+bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
/************************************************
diff --git a/third_party/nanopb/pb_encode.c b/third_party/nanopb/pb_encode.c
index cc372b8f57..4685614cf7 100644
--- a/third_party/nanopb/pb_encode.c
+++ b/third_party/nanopb/pb_encode.c
@@ -22,7 +22,7 @@
**************************************/
typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
-static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
+static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
@@ -49,16 +49,17 @@ 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_bytes /* PB_LTYPE_FIXED_LENGTH_BYTES */
};
/*******************************
* pb_ostream_t implementation *
*******************************/
-static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
+static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
- uint8_t *dest = (uint8_t*)stream->state;
+ pb_byte_t *dest = (pb_byte_t*)stream->state;
stream->state = dest + count;
while (count--)
@@ -67,7 +68,7 @@ static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size
return true;
}
-pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
+pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
{
pb_ostream_t stream;
#ifdef PB_BUFFER_ONLY
@@ -84,7 +85,7 @@ pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
return stream;
}
-bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
+bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
if (stream->callback != NULL)
{
@@ -413,15 +414,18 @@ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *sr
********************/
bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
{
- uint8_t buffer[10];
+ pb_byte_t buffer[10];
size_t i = 0;
- if (value == 0)
- return pb_write(stream, (uint8_t*)&value, 1);
+ if (value <= 0x7F)
+ {
+ pb_byte_t v = (pb_byte_t)value;
+ return pb_write(stream, &v, 1);
+ }
while (value)
{
- buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
+ buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80);
value >>= 7;
i++;
}
@@ -443,36 +447,28 @@ bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
{
- #ifdef __BIG_ENDIAN__
- const uint8_t *bytes = value;
- uint8_t lebytes[4];
- lebytes[0] = bytes[3];
- lebytes[1] = bytes[2];
- lebytes[2] = bytes[1];
- lebytes[3] = bytes[0];
- return pb_write(stream, lebytes, 4);
- #else
- return pb_write(stream, (const uint8_t*)value, 4);
- #endif
+ uint32_t val = *(const uint32_t*)value;
+ pb_byte_t bytes[4];
+ bytes[0] = (pb_byte_t)(val & 0xFF);
+ bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
+ bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
+ bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
+ return pb_write(stream, bytes, 4);
}
bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
{
- #ifdef __BIG_ENDIAN__
- const uint8_t *bytes = value;
- uint8_t lebytes[8];
- lebytes[0] = bytes[7];
- lebytes[1] = bytes[6];
- lebytes[2] = bytes[5];
- lebytes[3] = bytes[4];
- lebytes[4] = bytes[3];
- lebytes[5] = bytes[2];
- lebytes[6] = bytes[1];
- lebytes[7] = bytes[0];
- return pb_write(stream, lebytes, 8);
- #else
- return pb_write(stream, (const uint8_t*)value, 8);
- #endif
+ uint64_t val = *(const uint64_t*)value;
+ pb_byte_t bytes[8];
+ bytes[0] = (pb_byte_t)(val & 0xFF);
+ bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
+ bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
+ bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
+ bytes[4] = (pb_byte_t)((val >> 32) & 0xFF);
+ bytes[5] = (pb_byte_t)((val >> 40) & 0xFF);
+ bytes[6] = (pb_byte_t)((val >> 48) & 0xFF);
+ bytes[7] = (pb_byte_t)((val >> 56) & 0xFF);
+ return pb_write(stream, bytes, 8);
}
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
@@ -503,6 +499,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;
@@ -513,7 +510,7 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t
return pb_encode_tag(stream, wiretype, field->tag);
}
-bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
+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))
return false;
@@ -577,16 +574,16 @@ static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *fi
{
int64_t value = 0;
- /* Cases 1 and 2 are for compilers that have smaller types for bool
- * or enums, and for int_size option. */
- 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");
- }
+ if (field->data_size == sizeof(int_least8_t))
+ value = *(const int_least8_t*)src;
+ else if (field->data_size == sizeof(int_least16_t))
+ 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
+ PB_RETURN_ERROR(stream, "invalid data_size");
return pb_encode_varint(stream, (uint64_t)value);
}
@@ -595,14 +592,16 @@ static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *f
{
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");
- }
+ if (field->data_size == sizeof(uint_least8_t))
+ value = *(const uint_least8_t*)src;
+ else if (field->data_size == sizeof(uint_least16_t))
+ 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
+ PB_RETURN_ERROR(stream, "invalid data_size");
return pb_encode_varint(stream, value);
}
@@ -611,14 +610,16 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f
{
int64_t value = 0;
- 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");
- }
+ if (field->data_size == sizeof(int_least8_t))
+ value = *(const int_least8_t*)src;
+ else if (field->data_size == sizeof(int_least16_t))
+ 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
+ PB_RETURN_ERROR(stream, "invalid data_size");
return pb_encode_svarint(stream, value);
}
@@ -637,11 +638,16 @@ 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;
+
+ if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES)
+ return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size);
+
+ 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);
}
@@ -665,7 +671,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
{
@@ -677,7 +683,7 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi
}
}
- return pb_encode_string(stream, (const uint8_t*)src, size);
+ return pb_encode_string(stream, (const pb_byte_t*)src, size);
}
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
diff --git a/third_party/nanopb/pb_encode.h b/third_party/nanopb/pb_encode.h
index e992c8dca1..d9909fb013 100644
--- a/third_party/nanopb/pb_encode.h
+++ b/third_party/nanopb/pb_encode.h
@@ -35,7 +35,7 @@ struct pb_ostream_s
*/
int *callback;
#else
- bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
+ bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation. */
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */
@@ -86,7 +86,7 @@ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *sr
* Alternatively, you can use a custom stream that writes directly to e.g.
* a file or a network socket.
*/
-pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize);
+pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize);
/* Pseudo-stream for measuring the size of a message without actually storing
* the encoded data.
@@ -106,7 +106,7 @@ pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize);
/* Function to write into a pb_ostream_t stream. You can use this if you need
* to append or prepend some custom headers to the message.
*/
-bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
+bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
/************************************************
@@ -130,7 +130,7 @@ bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
-bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size);
+bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
/* Encode a fixed32, sfixed32 or float value.
* You need to pass a pointer to a 4-byte wide C variable. */
diff --git a/third_party/nanopb/tests/anonymous_oneof/SConscript b/third_party/nanopb/tests/anonymous_oneof/SConscript
new file mode 100644
index 0000000000..106722875f
--- /dev/null
+++ b/third_party/nanopb/tests/anonymous_oneof/SConscript
@@ -0,0 +1,30 @@
+# Test anonymous_oneof generator option
+
+Import('env')
+
+import re
+
+match = None
+if 'PROTOC_VERSION' in env:
+ match = re.search('([0-9]+).([0-9]+).([0-9]+)', env['PROTOC_VERSION'])
+
+if match:
+ version = map(int, match.groups())
+
+# Oneof is supported by protoc >= 2.6.0
+if env.GetOption('clean') or (match and (version[0] > 2 or (version[0] == 2 and version[1] >= 6))):
+ # Anonymous oneofs are supported by clang and gcc
+ if 'clang' in env['CC'] or 'gcc' in env['CC']:
+ env2 = env.Clone()
+ if '-pedantic' in env2['CFLAGS']:
+ env2['CFLAGS'].remove('-pedantic')
+ env2.NanopbProto('oneof')
+
+ dec = env2.Program(['decode_oneof.c',
+ 'oneof.pb.c',
+ '$COMMON/pb_decode.o',
+ '$COMMON/pb_common.o'])
+
+ env2.RunTest("message1.txt", [dec, '$BUILD/oneof/message1.pb'], ARGS = ['1'])
+ env2.RunTest("message2.txt", [dec, '$BUILD/oneof/message2.pb'], ARGS = ['2'])
+ env2.RunTest("message3.txt", [dec, '$BUILD/oneof/message3.pb'], ARGS = ['3'])
diff --git a/third_party/nanopb/tests/anonymous_oneof/decode_oneof.c b/third_party/nanopb/tests/anonymous_oneof/decode_oneof.c
new file mode 100644
index 0000000000..0f774dbc90
--- /dev/null
+++ b/third_party/nanopb/tests/anonymous_oneof/decode_oneof.c
@@ -0,0 +1,88 @@
+/* Decode a message using oneof fields */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pb_decode.h>
+#include "oneof.pb.h"
+#include "test_helpers.h"
+#include "unittests.h"
+
+/* Test the 'AnonymousOneOfMessage' */
+int test_oneof_1(pb_istream_t *stream, int option)
+{
+ AnonymousOneOfMessage msg;
+ int status = 0;
+
+ /* To better catch initialization errors */
+ memset(&msg, 0xAA, sizeof(msg));
+
+ if (!pb_decode(stream, AnonymousOneOfMessage_fields, &msg))
+ {
+ printf("Decoding failed: %s\n", PB_GET_ERROR(stream));
+ return 1;
+ }
+
+ /* Check that the basic fields work normally */
+ TEST(msg.prefix == 123);
+ TEST(msg.suffix == 321);
+
+ /* Check that we got the right oneof according to command line */
+ if (option == 1)
+ {
+ TEST(msg.which_values == AnonymousOneOfMessage_first_tag);
+ TEST(msg.first == 999);
+ }
+ else if (option == 2)
+ {
+ TEST(msg.which_values == AnonymousOneOfMessage_second_tag);
+ TEST(strcmp(msg.second, "abcd") == 0);
+ }
+ else if (option == 3)
+ {
+ TEST(msg.which_values == AnonymousOneOfMessage_third_tag);
+ TEST(msg.third.array[0] == 1);
+ TEST(msg.third.array[1] == 2);
+ TEST(msg.third.array[2] == 3);
+ TEST(msg.third.array[3] == 4);
+ TEST(msg.third.array[4] == 5);
+ }
+
+ return status;
+}
+
+int main(int argc, char **argv)
+{
+ uint8_t buffer[AnonymousOneOfMessage_size];
+ size_t count;
+ int option;
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "Usage: decode_oneof [number]\n");
+ return 1;
+ }
+ option = atoi(argv[1]);
+
+ SET_BINARY_MODE(stdin);
+ count = fread(buffer, 1, sizeof(buffer), stdin);
+
+ if (!feof(stdin))
+ {
+ printf("Message does not fit in buffer\n");
+ return 1;
+ }
+
+ {
+ int status = 0;
+ pb_istream_t stream;
+
+ stream = pb_istream_from_buffer(buffer, count);
+ status = test_oneof_1(&stream, option);
+
+ if (status != 0)
+ return status;
+ }
+
+ return 0;
+}
diff --git a/third_party/nanopb/tests/anonymous_oneof/oneof.proto b/third_party/nanopb/tests/anonymous_oneof/oneof.proto
new file mode 100644
index 0000000000..d56285c04d
--- /dev/null
+++ b/third_party/nanopb/tests/anonymous_oneof/oneof.proto
@@ -0,0 +1,23 @@
+syntax = "proto2";
+
+import 'nanopb.proto';
+
+message SubMessage
+{
+ repeated int32 array = 1 [(nanopb).max_count = 8];
+}
+
+/* Oneof in a message with other fields */
+message AnonymousOneOfMessage
+{
+ option (nanopb_msgopt).anonymous_oneof = true;
+ required int32 prefix = 1;
+ oneof values
+ {
+ int32 first = 5;
+ string second = 6 [(nanopb).max_size = 8];
+ SubMessage third = 7;
+ }
+ required int32 suffix = 99;
+}
+
diff --git a/third_party/nanopb/tests/fuzztest/fuzztest.c b/third_party/nanopb/tests/fuzztest/fuzztest.c
index d370172400..ee851ec089 100644
--- a/third_party/nanopb/tests/fuzztest/fuzztest.c
+++ b/third_party/nanopb/tests/fuzztest/fuzztest.c
@@ -192,6 +192,7 @@ static bool do_static_encode(uint8_t *buffer, size_t *msglen)
assert(stream.bytes_written <= alltypes_static_AllTypes_size);
*msglen = stream.bytes_written;
+ pb_release(alltypes_static_AllTypes_fields, msg);
free_with_check(msg);
return status;
diff --git a/third_party/nanopb/tests/inline/SConscript b/third_party/nanopb/tests/inline/SConscript
new file mode 100644
index 0000000000..34371fda18
--- /dev/null
+++ b/third_party/nanopb/tests/inline/SConscript
@@ -0,0 +1,16 @@
+# Test that inlined bytes fields work.
+
+Import("env")
+
+env.NanopbProto("inline")
+env.Object("inline.pb.c")
+
+env.Match(["inline.pb.h", "inline.expected"])
+
+p = env.Program(["inline_unittests.c",
+ "inline.pb.c",
+ "$COMMON/pb_encode.o",
+ "$COMMON/pb_decode.o",
+ "$COMMON/pb_common.o"])
+
+env.RunTest(p)
diff --git a/third_party/nanopb/tests/inline/inline.expected b/third_party/nanopb/tests/inline/inline.expected
new file mode 100644
index 0000000000..593e972bac
--- /dev/null
+++ b/third_party/nanopb/tests/inline/inline.expected
@@ -0,0 +1,3 @@
+pb_byte_t data\[32\];
+bool has_data;
+pb_byte_t data\[64\];
diff --git a/third_party/nanopb/tests/inline/inline.proto b/third_party/nanopb/tests/inline/inline.proto
new file mode 100644
index 0000000000..6e511f0a25
--- /dev/null
+++ b/third_party/nanopb/tests/inline/inline.proto
@@ -0,0 +1,17 @@
+/* Test nanopb option parsing.
+ * options.expected lists the patterns that are searched for in the output.
+ */
+
+syntax = "proto2";
+
+import "nanopb.proto";
+
+message Message1
+{
+ required bytes data = 1 [(nanopb).type = FT_INLINE, (nanopb).max_size = 32];
+}
+
+message Message2
+{
+ optional bytes data = 1 [(nanopb).type = FT_INLINE, (nanopb).max_size = 64];
+}
diff --git a/third_party/nanopb/tests/inline/inline_unittests.c b/third_party/nanopb/tests/inline/inline_unittests.c
new file mode 100644
index 0000000000..b5834c7e02
--- /dev/null
+++ b/third_party/nanopb/tests/inline/inline_unittests.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <string.h>
+#include <pb_decode.h>
+#include <pb_encode.h>
+#include "unittests.h"
+#include "inline.pb.h"
+
+int main()
+{
+ int status = 0;
+ int i = 0;
+ COMMENT("Test inline byte fields");
+
+ {
+ Message1 msg1 = Message1_init_zero;
+ TEST(sizeof(msg1.data) == 32);
+ }
+
+ {
+ Message1 msg1 = Message1_init_zero;
+ pb_byte_t msg1_buffer[Message1_size];
+ pb_ostream_t ostream = pb_ostream_from_buffer(msg1_buffer, Message1_size);
+ Message1 msg1_deserialized = Message1_init_zero;
+ pb_istream_t istream = pb_istream_from_buffer(msg1_buffer, Message1_size);
+
+ for (i = 0; i < 32; i++) {
+ msg1.data[i] = i;
+ }
+
+ TEST(pb_encode(&ostream, Message1_fields, &msg1));
+ TEST(ostream.bytes_written == Message1_size);
+
+ TEST(pb_decode(&istream, Message1_fields, &msg1_deserialized));
+
+ TEST(istream.bytes_left == 0);
+ TEST(memcmp(&msg1_deserialized, &msg1, sizeof(msg1)) == 0);
+ }
+
+ {
+ Message2 msg2 = {true, {0}};
+ Message2 msg2_no_data = {false, {1}};
+ pb_byte_t msg2_buffer[Message2_size];
+ pb_ostream_t ostream = pb_ostream_from_buffer(msg2_buffer, Message2_size);
+ Message2 msg2_deserialized = Message2_init_zero;
+ pb_istream_t istream = pb_istream_from_buffer(msg2_buffer, Message2_size);
+
+ for (i = 0; i < 64; i++) {
+ msg2.data[i] = i;
+ }
+
+ TEST(pb_encode(&ostream, Message2_fields, &msg2));
+ TEST(ostream.bytes_written == Message2_size);
+
+ TEST(pb_decode(&istream, Message2_fields, &msg2_deserialized));
+
+ TEST(istream.bytes_left == 0);
+ TEST(memcmp(&msg2_deserialized, &msg2, sizeof(msg2)) == 0);
+ TEST(msg2_deserialized.has_data);
+
+ memset(msg2_buffer, 0, sizeof(msg2_buffer));
+ ostream = pb_ostream_from_buffer(msg2_buffer, Message2_size);
+ TEST(pb_encode(&ostream, Message2_fields, &msg2_no_data));
+ istream = pb_istream_from_buffer(msg2_buffer, Message2_size);
+ TEST(pb_decode(&istream, Message2_fields, &msg2_deserialized));
+ TEST(!msg2_deserialized.has_data);
+ TEST(memcmp(&msg2_deserialized, &msg2, sizeof(msg2)) != 0);
+ }
+
+ if (status != 0)
+ fprintf(stdout, "\n\nSome tests FAILED!\n");
+
+ return status;
+}
diff --git a/third_party/nanopb/tests/mem_release/mem_release.c b/third_party/nanopb/tests/mem_release/mem_release.c
index 40fdc9e41e..dc6f87dea4 100644
--- a/third_party/nanopb/tests/mem_release/mem_release.c
+++ b/third_party/nanopb/tests/mem_release/mem_release.c
@@ -25,6 +25,8 @@ static void fill_TestMessage(TestMessage *msg)
msg->static_req_submsg.dynamic_submsg = test_msg_arr;
msg->static_req_submsg.dynamic_submsg[1].dynamic_str = "abc";
msg->static_opt_submsg.dynamic_str = "abc";
+ msg->static_rep_submsg_count = 2;
+ msg->static_rep_submsg[1].dynamic_str = "abc";
msg->has_static_opt_submsg = true;
msg->dynamic_submsg = &msg->static_req_submsg;
diff --git a/third_party/nanopb/tests/mem_release/mem_release.proto b/third_party/nanopb/tests/mem_release/mem_release.proto
index c3b38c8b5d..0816dc22d6 100644
--- a/third_party/nanopb/tests/mem_release/mem_release.proto
+++ b/third_party/nanopb/tests/mem_release/mem_release.proto
@@ -13,6 +13,7 @@ message TestMessage
required SubMessage static_req_submsg = 1 [(nanopb).type = FT_STATIC];
optional SubMessage dynamic_submsg = 2 [(nanopb).type = FT_POINTER];
optional SubMessage static_opt_submsg = 3 [(nanopb).type = FT_STATIC];
+ repeated SubMessage static_rep_submsg = 4 [(nanopb).type = FT_STATIC, (nanopb).max_count=2];
extensions 100 to 200;
}
diff --git a/third_party/nanopb/tests/multiple_files/SConscript b/third_party/nanopb/tests/multiple_files/SConscript
index 1689f4822a..b1281e1738 100644
--- a/third_party/nanopb/tests/multiple_files/SConscript
+++ b/third_party/nanopb/tests/multiple_files/SConscript
@@ -4,10 +4,13 @@ Import("env")
incpath = env.Clone()
incpath.Append(PROTOCPATH = '#multiple_files')
+incpath.Append(CPPPATH = '$BUILD/multiple_files')
incpath.NanopbProto(["multifile1", "multifile1.options"])
incpath.NanopbProto("multifile2")
-test = incpath.Program(["test_multiple_files.c", "multifile1.pb.c", "multifile2.pb.c"])
+incpath.NanopbProto("subdir/multifile2")
+test = incpath.Program(["test_multiple_files.c", "multifile1.pb.c",
+ "multifile2.pb.c", "subdir/multifile2.pb.c"])
env.RunTest(test)
diff --git a/third_party/nanopb/tests/multiple_files/subdir/multifile2.proto b/third_party/nanopb/tests/multiple_files/subdir/multifile2.proto
new file mode 100644
index 0000000000..847a929036
--- /dev/null
+++ b/third_party/nanopb/tests/multiple_files/subdir/multifile2.proto
@@ -0,0 +1,25 @@
+syntax = "proto2";
+
+package subdir;
+
+import "multifile1.proto";
+
+message Callback2Message {
+ required TestMessage tstmsg = 1;
+ required SubMessage submsg = 2;
+}
+
+message OneofMessage {
+ oneof msgs {
+ StaticMessage tstmsg = 1;
+ }
+}
+
+message Enums {
+ required SignedEnum senum = 1;
+ required UnsignedEnum uenum = 2;
+}
+
+message SubdirMessage {
+ required int32 foo = 1 [default = 15];
+}
diff --git a/third_party/nanopb/tests/multiple_files/test_multiple_files.c b/third_party/nanopb/tests/multiple_files/test_multiple_files.c
index 292b8d7c61..70a3e59641 100644
--- a/third_party/nanopb/tests/multiple_files/test_multiple_files.c
+++ b/third_party/nanopb/tests/multiple_files/test_multiple_files.c
@@ -6,6 +6,7 @@
#include <pb_encode.h>
#include "unittests.h"
#include "multifile2.pb.h"
+#include "subdir/multifile2.pb.h"
int main()
{
@@ -18,5 +19,12 @@ int main()
TEST(PB_LTYPE(Enums_fields[0].type) == PB_LTYPE_VARINT);
TEST(PB_LTYPE(Enums_fields[1].type) == PB_LTYPE_UVARINT);
+ /* Test that subdir file is correctly included */
+ {
+ subdir_SubdirMessage foo = subdir_SubdirMessage_init_default;
+ TEST(foo.foo == 15);
+ /* TEST(subdir_OneofMessage_size == 27); */ /* TODO: Issue #172 */
+ }
+
return status;
}
diff --git a/third_party/nanopb/tests/regression/issue_188/SConscript b/third_party/nanopb/tests/regression/issue_188/SConscript
new file mode 100644
index 0000000000..6bc32712b1
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_188/SConscript
@@ -0,0 +1,6 @@
+# Regression test for issue with Enums inside OneOf.
+
+Import('env')
+
+env.NanopbProto('oneof')
+
diff --git a/third_party/nanopb/tests/regression/issue_188/oneof.proto b/third_party/nanopb/tests/regression/issue_188/oneof.proto
new file mode 100644
index 0000000000..e37f5c0276
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_188/oneof.proto
@@ -0,0 +1,29 @@
+syntax = "proto2";
+
+message MessageOne
+{
+ required uint32 one = 1;
+ required uint32 two = 2;
+ required uint32 three = 3;
+ required int32 four = 4;
+}
+
+enum EnumTwo
+{
+ SOME_ENUM_1 = 1;
+ SOME_ENUM_2 = 5;
+ SOME_ENUM_3 = 6;
+ SOME_ENUM_4 = 9;
+ SOME_ENUM_5 = 10;
+ SOME_ENUM_6 = 12;
+ SOME_ENUM_7 = 39;
+ SOME_ENUM_8 = 401;
+}
+
+message OneofMessage
+{
+ oneof payload {
+ MessageOne message = 1;
+ EnumTwo enum = 2;
+ }
+}
diff --git a/third_party/nanopb/tests/regression/issue_195/SConscript b/third_party/nanopb/tests/regression/issue_195/SConscript
new file mode 100644
index 0000000000..78326d325e
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_195/SConscript
@@ -0,0 +1,10 @@
+# Regression test for Issue 195: Message size not calculated if a submessage includes
+# bytes. Basically a non-working #define being generated.
+
+Import("env")
+
+env.NanopbProto(["test"])
+env.Object('test.pb.c')
+
+env.Match(['test.pb.h', 'test.expected'])
+
diff --git a/third_party/nanopb/tests/regression/issue_195/test.expected b/third_party/nanopb/tests/regression/issue_195/test.expected
new file mode 100644
index 0000000000..83ea7ab869
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_195/test.expected
@@ -0,0 +1 @@
+/\* TestMessage_size depends
diff --git a/third_party/nanopb/tests/regression/issue_195/test.proto b/third_party/nanopb/tests/regression/issue_195/test.proto
new file mode 100644
index 0000000000..7a77d69dc5
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_195/test.proto
@@ -0,0 +1,8 @@
+message TestMessage {
+ required uint32 id = 1;
+ required bytes payload = 2;
+}
+message EncapsulatedMessage {
+ required uint32 id = 1;
+ required TestMessage test = 2;
+}
diff --git a/third_party/nanopb/tests/regression/issue_203/SConscript b/third_party/nanopb/tests/regression/issue_203/SConscript
new file mode 100644
index 0000000000..8b4d6cc702
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_203/SConscript
@@ -0,0 +1,9 @@
+# Regression test for issue with multiple files generated at once
+
+Import('env')
+
+env.Command(['file1.pb.c', 'file1.pb.h', 'file2.pb.c', 'file2.pb.h'], ['file1.proto', 'file2.proto'],
+ env['NANOPB_PROTO_CMD'])
+
+env.Object('file1.pb.c')
+env.Object('file2.pb.c')
diff --git a/third_party/nanopb/tests/regression/issue_203/file1.proto b/third_party/nanopb/tests/regression/issue_203/file1.proto
new file mode 100644
index 0000000000..dae250b842
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_203/file1.proto
@@ -0,0 +1,10 @@
+syntax = "proto2";
+
+message SubMessage1 {
+ required int32 foo = 1;
+}
+
+message Message1 {
+ required SubMessage1 bar = 1;
+}
+
diff --git a/third_party/nanopb/tests/regression/issue_203/file2.proto b/third_party/nanopb/tests/regression/issue_203/file2.proto
new file mode 100644
index 0000000000..513b0f0d77
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_203/file2.proto
@@ -0,0 +1,10 @@
+syntax = "proto2";
+
+message SubMessage2 {
+ required int32 foo = 1;
+}
+
+message Message2 {
+ required SubMessage2 bar = 1;
+}
+
diff --git a/third_party/nanopb/tests/regression/issue_205/SConscript b/third_party/nanopb/tests/regression/issue_205/SConscript
new file mode 100644
index 0000000000..ed8899ddfc
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_205/SConscript
@@ -0,0 +1,14 @@
+# Check that pb_release() correctly handles corrupted size fields of
+# static arrays.
+
+Import('env', 'malloc_env')
+
+env.NanopbProto('size_corruption')
+
+p = malloc_env.Program(["size_corruption.c",
+ "size_corruption.pb.c",
+ "$COMMON/pb_decode_with_malloc.o",
+ "$COMMON/pb_common_with_malloc.o",
+ "$COMMON/malloc_wrappers.o"])
+env.RunTest(p)
+
diff --git a/third_party/nanopb/tests/regression/issue_205/size_corruption.c b/third_party/nanopb/tests/regression/issue_205/size_corruption.c
new file mode 100644
index 0000000000..08cef45786
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_205/size_corruption.c
@@ -0,0 +1,12 @@
+#include "size_corruption.pb.h"
+#include <pb_decode.h>
+
+int main()
+{
+ MainMessage msg = MainMessage_init_zero;
+ msg.bar_count = (pb_size_t)-1;
+ pb_release(MainMessage_fields, &msg);
+
+ return 0;
+}
+
diff --git a/third_party/nanopb/tests/regression/issue_205/size_corruption.proto b/third_party/nanopb/tests/regression/issue_205/size_corruption.proto
new file mode 100644
index 0000000000..6c9c2453ab
--- /dev/null
+++ b/third_party/nanopb/tests/regression/issue_205/size_corruption.proto
@@ -0,0 +1,11 @@
+syntax = "proto2";
+import 'nanopb.proto';
+
+message SubMessage {
+ repeated int32 foo = 1 [(nanopb).type = FT_POINTER];
+}
+
+message MainMessage {
+ repeated SubMessage bar = 1 [(nanopb).max_count = 5];
+}
+
diff --git a/third_party/nanopb/tests/site_scons/site_tools/nanopb.py b/third_party/nanopb/tests/site_scons/site_tools/nanopb.py
index b3e58fa13c..c72a45d3b4 100644
--- a/third_party/nanopb/tests/site_scons/site_tools/nanopb.py
+++ b/third_party/nanopb/tests/site_scons/site_tools/nanopb.py
@@ -118,7 +118,7 @@ def generate(env):
env.SetDefault(PROTOCPATH = ['.', os.path.join(env['NANOPB'], 'generator', 'proto')])
- env.SetDefault(NANOPB_PROTO_CMD = '$PROTOC $PROTOC_OPTS --nanopb_out=. $SOURCE')
+ env.SetDefault(NANOPB_PROTO_CMD = '$PROTOC $PROTOCFLAGS --nanopb_out=. $SOURCES')
env['BUILDERS']['NanopbProto'] = _nanopb_proto_builder
def exists(env):
diff --git a/third_party/thrift b/third_party/thrift
new file mode 160000
+Subproject bcad91771b7f0bff28a1cac1981d7ef2b9bcef3