diff options
author | Amaury Medeiros <amaurym@google.com> | 2016-09-05 16:18:54 +0100 |
---|---|---|
committer | Amaury Medeiros <amaurym@google.com> | 2016-09-07 16:27:16 +0100 |
commit | ce0567cd1ff5c95a434bb118ba0db224e280e7d5 (patch) | |
tree | 25e697b985f5e9e41201bff97d72645a7d8153b5 | |
parent | 972589286388f16194b988dc0729f8ebfed3eaf9 (diff) | |
download | nanopb-c-ce0567cd1ff5c95a434bb118ba0db224e280e7d5.tar.gz |
Updates nanopb from upstream/masterstudio-2.3gradle_2.3.0
Updates it to nanopb@91bb64a, which includes nanopb-0.3.6 and also a
bazel BUILD file.
Change-Id: Ide3d6767d94c2b7bf9a9f902c82ced14be5e1761
-rw-r--r-- | .gitignore | 29 | ||||
-rw-r--r-- | AUTHORS | 24 | ||||
-rw-r--r-- | BUILD | 21 | ||||
-rw-r--r-- | CHANGELOG.txt | 9 | ||||
-rw-r--r-- | CONTRIBUTING.md | 32 | ||||
-rw-r--r-- | docs/concepts.rst | 6 | ||||
-rw-r--r-- | docs/index.rst | 4 | ||||
-rw-r--r-- | docs/reference.rst | 49 | ||||
-rwxr-xr-x | generator/nanopb_generator.py | 42 | ||||
-rw-r--r-- | generator/proto/nanopb.proto | 1 | ||||
-rw-r--r-- | generator/proto/nanopb_pb2.py | 13 | ||||
-rw-r--r-- | pb.h | 29 | ||||
-rw-r--r-- | pb_decode.c | 9 | ||||
-rw-r--r-- | pb_encode.c | 15 | ||||
-rw-r--r-- | tests/inline/SConscript | 16 | ||||
-rw-r--r-- | tests/inline/inline.expected | 3 | ||||
-rw-r--r-- | tests/inline/inline.proto | 17 | ||||
-rw-r--r-- | tests/inline/inline_unittests.c | 73 | ||||
-rw-r--r-- | tests/multiple_files/SConscript | 5 | ||||
-rw-r--r-- | tests/multiple_files/subdir/multifile2.proto | 25 | ||||
-rw-r--r-- | tests/multiple_files/test_multiple_files.c | 10 |
21 files changed, 383 insertions, 49 deletions
@@ -1,2 +1,29 @@ -*.pyc *.swp +*.gcda +*.gcno +*.gcov +*.o +*.pb.c +*.pb.h +*.pb +*.pyc +*_pb2.py +*~ +*.tar.gz +.sconsign.dblite +config.log +.sconf_temp +tests/build +julkaisu.txt +dist +docs/*.html +docs/generator_flow.png +examples/simple/simple +examples/network_server/client +examples/network_server/server +examples/using_double_on_avr/decode_double +examples/using_double_on_avr/encode_double +examples/using_double_on_avr/test_conversions +examples/using_union_messages/decode +examples/using_union_messages/encode +generator/nanopb_pb2.pyc @@ -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> @@ -0,0 +1,21 @@ +licenses(["notice"]) + +exports_files(["LICENSE.txt"]) + +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/CHANGELOG.txt b/CHANGELOG.txt index fd983df..8437688 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,12 @@ +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. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4041bc3 --- /dev/null +++ b/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/docs/concepts.rst b/docs/concepts.rst index b4f657e..ea33863 100644 --- a/docs/concepts.rst +++ b/docs/concepts.rst @@ -148,7 +148,8 @@ 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 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. +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. +4) 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. =============================================================================== ======================= field in .proto autogenerated in .h @@ -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. diff --git a/docs/index.rst b/docs/index.rst index 2432857..afc7ee4 100644 --- a/docs/index.rst +++ b/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 ================= @@ -54,7 +54,7 @@ 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.. +#) 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/docs/reference.rst b/docs/reference.rst index 7d27a51..ef3867a 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -77,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. @@ -216,17 +218,20 @@ Type used to store the type of each field, to control the encoder/decoder behavi 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: @@ -489,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 ---------------- diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py index 84f5d09..973c761 100755 --- a/generator/nanopb_generator.py +++ b/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.6-dev" +nanopb_version = "nanopb-0.3.7-dev" import sys import re @@ -241,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 @@ -319,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' @@ -359,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 = '' @@ -388,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: @@ -400,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']: @@ -454,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) @@ -481,7 +502,7 @@ class 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 @@ -594,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;' @@ -671,6 +693,7 @@ class OneOf(Field): self.default = None self.rules = 'ONEOF' self.anonymous = False + self.inline = None def add_field(self, field): if field.allocation == 'CALLBACK': @@ -1045,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: diff --git a/generator/proto/nanopb.proto b/generator/proto/nanopb.proto index 9b2f0fb..8aab19a 100644 --- a/generator/proto/nanopb.proto +++ b/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 { diff --git a/generator/proto/nanopb_pb2.py b/generator/proto/nanopb_pb2.py index 3b86d16..31f9cbc 100644 --- a/generator/proto/nanopb_pb2.py +++ b/generator/proto/nanopb_pb2.py @@ -15,7 +15,7 @@ import google.protobuf.descriptor_pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='nanopb.proto', package='', - serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\xbc\x02\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse*Z\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB\x1a\n\x18\x66i.kapsi.koti.jpa.nanopb') + serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\xbc\x02\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse*i\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03\x12\r\n\tFT_INLINE\x10\x05*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB\x1a\n\x18\x66i.kapsi.koti.jpa.nanopb') _FIELDTYPE = _descriptor.EnumDescriptor( name='FieldType', @@ -43,11 +43,15 @@ _FIELDTYPE = _descriptor.EnumDescriptor( name='FT_IGNORE', index=4, number=3, options=None, type=None), + _descriptor.EnumValueDescriptor( + name='FT_INLINE', index=5, number=5, + options=None, + type=None), ], containing_type=None, options=None, serialized_start=369, - serialized_end=459, + serialized_end=474, ) FieldType = enum_type_wrapper.EnumTypeWrapper(_FIELDTYPE) @@ -80,8 +84,8 @@ _INTSIZE = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=461, - serialized_end=529, + serialized_start=476, + serialized_end=544, ) IntSize = enum_type_wrapper.EnumTypeWrapper(_INTSIZE) @@ -90,6 +94,7 @@ FT_CALLBACK = 1 FT_POINTER = 4 FT_STATIC = 2 FT_IGNORE = 3 +FT_INLINE = 5 IS_DEFAULT = 0 IS_8 = 8 IS_16 = 16 @@ -46,7 +46,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.3.6-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: @@ -170,8 +170,14 @@ typedef uint_least8_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 ****/ @@ -415,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, \ @@ -454,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) @@ -485,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 @@ -511,6 +532,8 @@ 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_ONEOF_ ## allocation(union_name, tag, message, field, \ PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ diff --git a/pb_decode.c b/pb_decode.c index 78911e7..7a4e29a 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -65,7 +65,8 @@ 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 */ }; /******************************* @@ -1272,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; diff --git a/pb_encode.c b/pb_encode.c index 9f91c9d..4685614 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -49,7 +49,8 @@ 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 */ }; /******************************* @@ -498,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; @@ -636,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); } @@ -664,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 { diff --git a/tests/inline/SConscript b/tests/inline/SConscript new file mode 100644 index 0000000..34371fd --- /dev/null +++ b/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/tests/inline/inline.expected b/tests/inline/inline.expected new file mode 100644 index 0000000..593e972 --- /dev/null +++ b/tests/inline/inline.expected @@ -0,0 +1,3 @@ +pb_byte_t data\[32\]; +bool has_data; +pb_byte_t data\[64\]; diff --git a/tests/inline/inline.proto b/tests/inline/inline.proto new file mode 100644 index 0000000..6e511f0 --- /dev/null +++ b/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/tests/inline/inline_unittests.c b/tests/inline/inline_unittests.c new file mode 100644 index 0000000..b5834c7 --- /dev/null +++ b/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/tests/multiple_files/SConscript b/tests/multiple_files/SConscript index 1689f48..b1281e1 100644 --- a/tests/multiple_files/SConscript +++ b/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/tests/multiple_files/subdir/multifile2.proto b/tests/multiple_files/subdir/multifile2.proto new file mode 100644 index 0000000..847a929 --- /dev/null +++ b/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/tests/multiple_files/test_multiple_files.c b/tests/multiple_files/test_multiple_files.c index 292b8d7..72718ab 100644 --- a/tests/multiple_files/test_multiple_files.c +++ b/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() { @@ -17,6 +18,13 @@ int main() /* Check that enum signedness is detected properly */ 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; } |