Compare commits

..

7 Commits

Author SHA1 Message Date
Petteri Aimonen
45fc9f3ef6 Publishing nanopb-0.2.9.1 2014-09-11 19:14:45 +03:00
Petteri Aimonen
115de6e555 Update changelog 2014-09-11 19:13:59 +03:00
Petteri Aimonen
9c92410e2a Add a better fuzz test.
Attempts to verify all the properties defined in the security model,
while also being portable and able to run on many platforms.
2014-09-11 18:25:23 +03:00
Petteri Aimonen
6df566859d Protect against size_t overflows in pb_dec_bytes/pb_dec_string.
Possible consequences of bug:
1) Denial of service by causing a crash
   Possible when all of the following apply:
      - Untrusted data is passed to pb_decode()
      - The top-level message contains a static string field as the first field.
   Causes a single write of '0' byte to 1 byte before the message struct.

2) Remote code execution
   Possible when all of the following apply:
      - 64-bit platform
      - The message or a submessage contains a static/pointer string field.
      - Decoding directly from a custom pb_istream_t
      - bytes_left on the stream is set to larger than 4 GB
   Causes a write of up to 4 GB of data past the string field.

3) Possible heap corruption or remote code execution
   Possible when all of the following apply:
      - less than 64-bit platform
      - The message or a submessage contains a pointer-type bytes field.
   Causes a write of sizeof(pb_size_t) bytes of data past a 0-byte long
   malloc()ed buffer. On many malloc() implementations, this causes at
   most a crash. However, remote code execution through a controlled jump
   cannot be ruled out.

--

Detailed analysis follows

In the following consideration, I define "platform bitness" as equal to
number of bits in size_t datatype. Therefore most 8-bit platforms are
regarded as 16-bit for the purposes of this discussion.

1. The overflow in pb_dec_string

The overflow happens in this computation:

uint32_t size;
size_t alloc_size;
alloc_size = size + 1;

There are two ways in which the overflow can occur: In the uint32_t
addition, or in the cast to size_t. This depends on the platform
bitness.

On 32- and 64-bit platforms, the size has to be UINT32_MAX for the
overflow to occur. In that case alloc_size will be 0.

On 16-bit platforms, overflow will happen whenever size is more than
UINT16_MAX, and resulting alloc_size is attacker controlled.

For static fields, the alloc_size value is just checked against the
field data size. For pointer fields, the alloc_size value is passed to
malloc(). End result in both cases is the same, the storage is 0 or
just a few bytes in length.

On 16-bit platforms, another overflow occurs in the call to pb_read(),
when passing the original size. An attacker will want the passed value
to be larger than the alloc_size, therefore the only reasonable choice
is to have size = UINT16_MAX and alloc_size = 0. Any larger multiple
will truncate to the same values.

At this point we have read atleast the tag and the string length of the
message, i.e. atleast 3 bytes. The maximum initial value for stream
bytes_left is SIZE_MAX, thus at this point at most SIZE_MAX-3 bytes are
remaining.

On 32-bit and 16-bit platforms this means that the size passed to
pb_read() is always larger than the number of remaining bytes. This
causes pb_read() to fail immediately, before reading any bytes.

On 64-bit platforms, it is possible for the bytes_left value to be set
to a value larger than UINT32_MAX, which is the wraparound point in
size calculation. In this case pb_read() will succeed and write up to 4
GB of attacker controlled data over the RAM that comes after the string
field.

On all platforms, there is an unconditional write of a terminating null
byte. Because the size of size_t typically reflects the size of the
processor address space, a write at UINT16_MAX or UINT32_MAX bytes
after the string field actually wraps back to before the string field.
Consequently, on 32-bit and 16-bit platforms, the bug causes a single
write of '0' byte at one byte before the string field.

If the string field is in the middle of a message, this will just
corrupt other data in the message struct. Because the message contents
is attacker controlled anyway, this is a non-issue. However, if the
string field is the first field in the top-level message, it can
corrupt other data on the stack/heap before it. Typically a single '0'
write at a location not controlled by attacker is enough only for a
denial-of-service attack.

When using pointer fields and malloc(), the attacker controlled
alloc_size will cause a 0-size allocation to happen. By the same logic
as before, on 32-bit and 16-bit platforms this causes a '0' byte write
only. On 64-bit platforms, however, it will again allow up to 4 GB of
malicious data to be written over memory, if the stream length allows
the read.

2. The overflow in pb_dec_bytes

This overflow happens in the PB_BYTES_ARRAY_T_ALLOCSIZE macro:

The computation is done in size_t data type this time. This means that
an overflow is possible only when n is larger than SIZE_MAX -
offsetof(..). The offsetof value in this case is equal to
sizeof(pb_size_t) bytes.

Because the incoming size value is limited to 32 bits, no overflow can
happen here on 64-bit platforms.

The size will be passed to pb_read(). Like before, on 32-bit and 16-bit
platforms the read will always fail before writing anything.

This leaves only the write of bdest->size as exploitable. On statically
allocated fields, the size field will always be allocated, regardless
of alloc_size. In this case, no buffer overflow is possible here, but
user code could possibly use the attacker controlled size value and
read past a buffer.

If the field is allocated through malloc(), this will allow a write of
sizeof(pb_size_t) attacker controlled bytes to past a 0-byte long
buffer. In typical malloc implementations, this will either fit in
unused alignment padding area, or cause a heap corruption and a crash.
Under very exceptional situation it could allow attacker to influence
the behaviour of malloc(), possibly jumping into an attacker-controlled
location and thus leading to remote code execution.
2014-09-11 18:25:23 +03:00
Petteri Aimonen
cc1c3a7963 Add just-to-be-sure check to allocate_field().
This check will help to detect bugs earlier, and is quite lightweight
compared to malloc() anyway.
2014-09-11 18:25:23 +03:00
Petteri Aimonen
33585924de Fix memory leak with duplicated fields and PB_ENABLE_MALLOC.
If a required or optional field appeared twice in the message data,
pb_decode will overwrite the old data with new one. That is fine, but
with submessage fields, it didn't release the allocated subfields before
overwriting.

This bug can manifest if all of the following conditions are true:

1. There is a message with a "optional" or "required" submessage field
   that has type:FT_POINTER.

2. The submessage contains atleast one field with type:FT_POINTER.

3. The message data to be decoded has the submessage field twice in it.
2014-09-11 18:25:18 +03:00
Petteri Aimonen
b7add1e577 Fix crash in pb_release() if called twice on same message.
There was a double-free bug in pb_release() because it didn't set size fields
to zero after deallocation. Most commonly this happens if pb_decode() fails,
internally calls pb_release() and then application code also calls pb_release().
2014-09-11 18:16:01 +03:00
87 changed files with 653 additions and 2905 deletions

View File

@@ -1,33 +1,7 @@
nanopb-0.3.2 (2015-01-24) nanopb-0.2.9.1 (2014-09-11)
Fix memory leaks with PB_ENABLE_MALLOC with some submessage hierarchies (issue 138)
Implement support for oneofs (C unions). (issues 131, 141)
Add int_size option for generator (issue 139)
Add compilation option to disable struct packing. (issue 136)
Change PB_RETURN_ERROR() macro to avoid compiler warnings (issue 140)
Fix build problems with protoc 3.0.0
Add support for POINTER type in extensions
Initialize also extension fields to defaults in pb_decode().
Detect too large varint values when decoding.
nanopb-0.3.1 (2014-09-11)
Fix security issue due to size_t overflows. (issue 132) Fix security issue due to size_t overflows. (issue 132)
Fix memory leak with duplicated fields and PB_ENABLE_MALLOC Fix memory leak with duplicated fields and PB_ENABLE_MALLOC
Fix crash if pb_release() is called twice. Fix crash if pb_release() is called twice.
Fix cyclic message support (issue 130)
Fix error in generated initializers for repeated pointer fields.
Improve tests (issues 113, 126)
nanopb-0.3.0 (2014-08-26)
NOTE: See docs/migration.html or online at
http://koti.kapsi.fi/~jpa/nanopb/docs/migration.html
for changes in this version. Most importantly, you need to add
pb_common.c to the list of files to compile.
Separated field iterator logic to pb_common.c (issue 128)
Change the _count fields to use pb_size_t datatype (issue 82)
Added PB_ prefix to macro names (issue 106)
Added #if version guard to generated files (issue 129)
Added migration document
nanopb-0.2.9 (2014-08-09) nanopb-0.2.9 (2014-08-09)
NOTE: If you are using the -e option with the generator, you have NOTE: If you are using the -e option with the generator, you have

View File

@@ -1,4 +1,4 @@
all: index.html concepts.html reference.html security.html migration.html \ all: index.html concepts.html reference.html security.html \
generator_flow.png generator_flow.png
%.png: %.svg %.png: %.svg

View File

@@ -4,10 +4,8 @@
2) `Concepts`_ 2) `Concepts`_
3) `API reference`_ 3) `API reference`_
4) `Security model`_ 4) `Security model`_
5) `Migration from older versions`_
.. _`Overview`: index.html .. _`Overview`: index.html
.. _`Concepts`: concepts.html .. _`Concepts`: concepts.html
.. _`API reference`: reference.html .. _`API reference`: reference.html
.. _`Security model`: security.html .. _`Security model`: security.html
.. _`Migration from older versions`: migration.html

View File

@@ -1,258 +0,0 @@
=====================================
Nanopb: Migration from older versions
=====================================
.. include :: menu.rst
This document details all the breaking changes that have been made to nanopb
since its initial release. For each change, the rationale and required
modifications of user applications are explained. Also any error indications
are included, in order to make it easier to find this document.
.. contents ::
Nanopb-0.3.2 (2015-01-24)
=========================
Add support for OneOfs
----------------------
**Rationale:** Previously nanopb did not support the *oneof* construct in
*.proto* files. Those fields were generated as regular *optional* fields.
**Changes:** OneOfs are now generated as C unions. Callback fields are not
supported inside oneof and generator gives an error.
**Required actions:** The generator option *no_unions* can be used to restore old
behaviour and to allow callbacks to be used. To use unions, one change is
needed: use *which_xxxx* field to detect which field is present, instead
of *has_xxxx*. Compare the value against *MyStruct_myfield_tag*.
**Error indications:** Generator error: "Callback fields inside of oneof are
not supported". Compiler error: "Message" has no member named "has_xxxx".
Nanopb-0.3.0 (2014-08-26)
=========================
Separate field iterator logic to pb_common.c
--------------------------------------------
**Rationale:** Originally, the field iteration logic was simple enough to be
duplicated in *pb_decode.c* and *pb_encode.c*. New field types have made the
logic more complex, which required the creation of a new file to contain the
common functionality.
**Changes:** There is a new file, *pb_common.c*, which must be included in
builds.
**Required actions:** Add *pb_common.c* to build rules. This file is always
required. Either *pb_decode.c* or *pb_encode.c* can still be left out if some
functionality is not needed.
**Error indications:** Linker error: undefined reference to
*pb_field_iter_begin*, *pb_field_iter_next* or similar.
Change data type of field counts to pb_size_t
---------------------------------------------
**Rationale:** Often nanopb is used with small arrays, such as 255 items or
less. Using a full *size_t* field to store the array count wastes memory if
there are many arrays. There already exists parameters *PB_FIELD_16BIT* and
*PB_FIELD_32BIT* which tell nanopb what is the maximum size of arrays in use.
**Changes:** Generator will now use *pb_size_t* for the array *_count* fields.
The size of the type will be controlled by the *PB_FIELD_16BIT* and
*PB_FIELD_32BIT* compilation time options.
**Required actions:** Regenerate all *.pb.h* files. In some cases casts to the
*pb_size_t* type may need to be added in the user code when accessing the
*_count* fields.
**Error indications:** Incorrect data at runtime, crashes. But note that other
changes in the same version already require regenerating the files and have
better indications of errors, so this is only an issue for development
versions.
Renamed some macros and identifiers
-----------------------------------
**Rationale:** Some names in nanopb core were badly chosen and conflicted with
ISO C99 reserved names or lacked a prefix. While they haven't caused trouble
so far, it is reasonable to switch to non-conflicting names as these are rarely
used from user code.
**Changes:** The following identifier names have changed:
* Macros:
* STATIC_ASSERT(x) -> PB_STATIC_ASSERT(x)
* UNUSED(x) -> PB_UNUSED(x)
* Include guards:
* _PB_filename_ -> PB_filename_INCLUDED
* Structure forward declaration tags:
* _pb_field_t -> pb_field_s
* _pb_bytes_array_t -> pb_bytes_array_s
* _pb_callback_t -> pb_callback_s
* _pb_extension_type_t -> pb_extension_type_s
* _pb_extension_t -> pb_extension_s
* _pb_istream_t -> pb_istream_s
* _pb_ostream_t -> pb_ostream_s
**Required actions:** Regenerate all *.pb.c* files. If you use any of the above
identifiers in your application code, perform search-replace to the new name.
**Error indications:** Compiler errors on lines with the macro/type names.
Nanopb-0.2.9 (2014-08-09)
=========================
Change semantics of generator -e option
---------------------------------------
**Rationale:** Some compilers do not accept filenames with two dots (like
in default extension .pb.c). The *-e* option to the generator allowed changing
the extension, but not skipping the extra dot.
**Changes:** The *-e* option in generator will no longer add the prepending
dot. The default value has been adjusted accordingly to *.pb.c* to keep the
default behaviour the same as before.
**Required actions:** Only if using the generator -e option. Add dot before
the parameter value on the command line.
**Error indications:** File not found when trying to compile generated files.
Nanopb-0.2.7 (2014-04-07)
=========================
Changed pointer-type bytes field datatype
-----------------------------------------
**Rationale:** In the initial pointer encoding support since nanopb-0.2.5,
the bytes type used a separate *pb_bytes_ptr_t* type to represent *bytes*
fields. This made it easy to encode data from a separate, user-allocated
buffer. However, it made the internal logic more complex and was inconsistent
with the other types.
**Changes:** Dynamically allocated bytes fields now have the *pb_bytes_array_t*
type, just like statically allocated ones.
**Required actions:** Only if using pointer-type fields with the bytes datatype.
Change any access to *msg->field.size* to *msg->field->size*. Change any
allocation to reserve space of amount *PB_BYTES_ARRAY_T_ALLOCSIZE(n)*. If the
data pointer was begin assigned from external source, implement the field using
a callback function instead.
**Error indications:** Compiler error: unknown type name *pb_bytes_ptr_t*.
Nanopb-0.2.4 (2013-11-07)
=========================
Remove the NANOPB_INTERNALS compilation option
----------------------------------------------
**Rationale:** Having the option in the headers required the functions to
be non-static, even if the option is not used. This caused errors on some
static analysis tools.
**Changes:** The *#ifdef* and associated functions were removed from the
header.
**Required actions:** Only if the *NANOPB_INTERNALS* option was previously
used. Actions are as listed under nanopb-0.1.3 and nanopb-0.1.6.
**Error indications:** Compiler warning: implicit declaration of function
*pb_dec_string*, *pb_enc_string*, or similar.
Nanopb-0.2.1 (2013-04-14)
=========================
Callback function signature
---------------------------
**Rationale:** Previously the auxilary data to field callbacks was passed
as *void\**. This allowed passing of any data, but made it unnecessarily
complex to return a pointer from callback.
**Changes:** The callback function parameter was changed to *void\*\**.
**Required actions:** You can continue using the old callback style by
defining *PB_OLD_CALLBACK_STYLE*. Recommended action is to:
* Change the callback signatures to contain *void\*\** for decoders and
*void \* const \** for encoders.
* Change the callback function body to use *\*arg* instead of *arg*.
**Error indications:** Compiler warning: assignment from incompatible
pointer type, when initializing *funcs.encode* or *funcs.decode*.
Nanopb-0.2.0 (2013-03-02)
=========================
Reformatted generated .pb.c file using macros
---------------------------------------------
**Rationale:** Previously the generator made a list of C *pb_field_t*
initializers in the .pb.c file. This led to a need to regenerate all .pb.c
files after even small changes to the *pb_field_t* definition.
**Changes:** Macros were added to pb.h which allow for cleaner definition
of the .pb.c contents. By changing the macro definitions, changes to the
field structure are possible without breaking compatibility with old .pb.c
files.
**Required actions:** Regenerate all .pb.c files from the .proto sources.
**Error indications:** Compiler warning: implicit declaration of function
*pb_delta_end*.
Changed pb_type_t definitions
-----------------------------
**Rationale:** The *pb_type_t* was previously an enumeration type. This
caused warnings on some compilers when using bitwise operations to set flags
inside the values.
**Changes:** The *pb_type_t* was changed to *typedef uint8_t*. The values
were changed to *#define*. Some value names were changed for consistency.
**Required actions:** Only if you directly access the `pb_field_t` contents
in your own code, something which is not usually done. Needed changes:
* Change *PB_HTYPE_ARRAY* to *PB_HTYPE_REPEATED*.
* Change *PB_HTYPE_CALLBACK* to *PB_ATYPE()* and *PB_ATYPE_CALLBACK*.
**Error indications:** Compiler error: *PB_HTYPE_ARRAY* or *PB_HTYPE_CALLBACK*
undeclared.
Nanopb-0.1.6 (2012-09-02)
=========================
Refactored field decoder interface
----------------------------------
**Rationale:** Similarly to field encoders in nanopb-0.1.3.
**Changes:** New functions with names *pb_decode_\** were added.
**Required actions:** By defining NANOPB_INTERNALS, you can still keep using
the old functions. Recommended action is to replace any calls with the newer
*pb_decode_\** equivalents.
**Error indications:** Compiler warning: implicit declaration of function
*pb_dec_string*, *pb_dec_varint*, *pb_dec_submessage* or similar.
Nanopb-0.1.3 (2012-06-12)
=========================
Refactored field encoder interface
----------------------------------
**Rationale:** The old *pb_enc_\** functions were designed mostly for the
internal use by the core. Because they are internally accessed through
function pointers, their signatures had to be common. This led to a confusing
interface for external users.
**Changes:** New functions with names *pb_encode_\** were added. These have
easier to use interfaces. The old functions are now only thin wrappers for
the new interface.
**Required actions:** By defining NANOPB_INTERNALS, you can still keep using
the old functions. Recommended action is to replace any calls with the newer
*pb_encode_\** equivalents.
**Error indications:** Compiler warning: implicit declaration of function
*pb_enc_string*, *pb_enc_varint, *pb_enc_submessage* or similar.

View File

@@ -24,9 +24,6 @@ __BIG_ENDIAN__ Set this if your platform stores integers and
floats in big-endian format. Mixed-endian floats in big-endian format. Mixed-endian
systems (different layout for ints and floats) systems (different layout for ints and floats)
are currently not supported. 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.
PB_ENABLE_MALLOC Set this to enable dynamic allocation support PB_ENABLE_MALLOC Set this to enable dynamic allocation support
in the decoder. in the decoder.
PB_MAX_REQUIRED_FIELDS Maximum number of required fields to check for PB_MAX_REQUIRED_FIELDS Maximum number of required fields to check for
@@ -76,8 +73,6 @@ The generator behaviour can be adjusted using these options, defined in the
max_size Allocated size for *bytes* and *string* fields. max_size Allocated size for *bytes* and *string* fields.
max_count Allocated number of entries in arrays max_count Allocated number of entries in arrays
(*repeated* fields). (*repeated* fields).
int_size Override the integer type of a field.
(To use e.g. uint8_t to save RAM.)
type Type of the generated field. Default value type Type of the generated field. Default value
is *FT_DEFAULT*, which selects automatically. is *FT_DEFAULT*, which selects automatically.
You can use *FT_CALLBACK*, *FT_POINTER*, You can use *FT_CALLBACK*, *FT_POINTER*,
@@ -90,7 +85,6 @@ long_names Prefix the enum name to the enum value in
packed_struct Make the generated structures packed. packed_struct Make the generated structures packed.
NOTE: This cannot be used on CPUs that break NOTE: This cannot be used on CPUs that break
on unaligned accesses to variables. on unaligned accesses to variables.
skip_message Skip the whole message from generation.
============================ ================================================ ============================ ================================================
These options can be defined for the .proto files before they are converted These options can be defined for the .proto files before they are converted

View File

@@ -26,9 +26,9 @@ The following data is regarded as **trusted**. It must be under the control of
the application writer. Malicious data in these structures could cause the application writer. Malicious data in these structures could cause
security issues, such as execution of arbitrary code: security issues, such as execution of arbitrary code:
1. Callback, pointer and extension fields in message structures given to 1. Callback and extension fields in message structures given to pb_encode()
pb_encode() and pb_decode(). These fields are memory pointers, and are and pb_decode(). These fields are memory pointers, and are generated
generated depending on the message definition in the .proto file. depending on the .proto file.
2. The automatically generated field definitions, i.e. *pb_field_t* lists. 2. The automatically generated field definitions, i.e. *pb_field_t* lists.
3. Contents of the *pb_istream_t* and *pb_ostream_t* structures (this does not 3. Contents of the *pb_istream_t* and *pb_ostream_t* structures (this does not
mean the contents of the stream itself, just the stream definition). mean the contents of the stream itself, just the stream definition).
@@ -38,7 +38,7 @@ these will cause "garbage in, garbage out" behaviour. It will not cause
buffer overflows, information disclosure or other security problems: buffer overflows, information disclosure or other security problems:
1. All data read from *pb_istream_t*. 1. All data read from *pb_istream_t*.
2. All fields in message structures, except callbacks, pointers and extensions. 2. All fields in message structures, except callbacks and extensions.
(Beginning with nanopb-0.2.4, in earlier versions the field sizes are partially unchecked.) (Beginning with nanopb-0.2.4, in earlier versions the field sizes are partially unchecked.)
Invariants Invariants
@@ -76,6 +76,4 @@ The following list is not comprehensive:
stop a denial of service attack from using an infinite message. stop a denial of service attack from using an infinite message.
4. If using network sockets as streams, a timeout should be set to stop 4. If using network sockets as streams, a timeout should be set to stop
denial of service attacks. denial of service attacks.
5. If using *malloc()* support, some method of limiting memory use should be
employed. This can be done by defining custom *pb_realloc()* function.
Nanopb will properly detect and handle failed memory allocations.

View File

@@ -10,7 +10,6 @@ CSRC = simple.c # The main program
CSRC += simple.pb.c # The compiled protocol definition CSRC += simple.pb.c # The compiled protocol definition
CSRC += $(NANOPB_DIR)/pb_encode.c # The nanopb encoder CSRC += $(NANOPB_DIR)/pb_encode.c # The nanopb encoder
CSRC += $(NANOPB_DIR)/pb_decode.c # The nanopb decoder CSRC += $(NANOPB_DIR)/pb_decode.c # The nanopb decoder
CSRC += $(NANOPB_DIR)/pb_common.c # The nanopb common parts
# Build rule for the main program # Build rule for the main program
simple: $(CSRC) simple: $(CSRC)

View File

@@ -182,8 +182,8 @@ mark_as_advanced(NANOPB_INCLUDE_DIRS)
# Find nanopb source files # Find nanopb source files
set(NANOPB_SRCS) set(NANOPB_SRCS)
set(NANOPB_HDRS) set(NANOPB_HDRS)
list(APPEND _nanopb_srcs pb_decode.c pb_encode.c pb_common.c) list(APPEND _nanopb_srcs pb_decode.c pb_encode.c)
list(APPEND _nanopb_hdrs pb_decode.h pb_encode.h pb_common.h pb.h) list(APPEND _nanopb_hdrs pb_decode.h pb_encode.h pb.h)
foreach(FIL ${_nanopb_srcs}) foreach(FIL ${_nanopb_srcs})
find_file(${FIL}__nano_pb_file NAMES ${FIL} PATHS ${NANOPB_SRC_ROOT_FOLDER} ${NANOPB_INCLUDE_DIRS}) find_file(${FIL}__nano_pb_file NAMES ${FIL} PATHS ${NANOPB_SRC_ROOT_FOLDER} ${NANOPB_INCLUDE_DIRS})

View File

@@ -5,7 +5,7 @@
NANOPB_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))../) NANOPB_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))../)
# Files for the nanopb core # Files for the nanopb core
NANOPB_CORE = $(NANOPB_DIR)/pb_encode.c $(NANOPB_DIR)/pb_decode.c $(NANOPB_DIR)/pb_common.c NANOPB_CORE = $(NANOPB_DIR)/pb_encode.c $(NANOPB_DIR)/pb_decode.c
# Check if we are running on Windows # Check if we are running on Windows
ifdef windir ifdef windir

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
nanopb_version = "nanopb-0.3.2" nanopb_version = "nanopb-0.2.9.1"
import sys import sys
@@ -44,30 +44,22 @@ except:
import time import time
import os.path import os.path
# Values are tuple (c type, pb type, encoded size, int_size_allowed) # Values are tuple (c type, pb type, encoded size)
FieldD = descriptor.FieldDescriptorProto FieldD = descriptor.FieldDescriptorProto
datatypes = { datatypes = {
FieldD.TYPE_BOOL: ('bool', 'BOOL', 1, False), FieldD.TYPE_BOOL: ('bool', 'BOOL', 1),
FieldD.TYPE_DOUBLE: ('double', 'DOUBLE', 8, False), FieldD.TYPE_DOUBLE: ('double', 'DOUBLE', 8),
FieldD.TYPE_FIXED32: ('uint32_t', 'FIXED32', 4, False), FieldD.TYPE_FIXED32: ('uint32_t', 'FIXED32', 4),
FieldD.TYPE_FIXED64: ('uint64_t', 'FIXED64', 8, False), FieldD.TYPE_FIXED64: ('uint64_t', 'FIXED64', 8),
FieldD.TYPE_FLOAT: ('float', 'FLOAT', 4, False), FieldD.TYPE_FLOAT: ('float', 'FLOAT', 4),
FieldD.TYPE_INT32: ('int32_t', 'INT32', 10, True), FieldD.TYPE_INT32: ('int32_t', 'INT32', 10),
FieldD.TYPE_INT64: ('int64_t', 'INT64', 10, True), FieldD.TYPE_INT64: ('int64_t', 'INT64', 10),
FieldD.TYPE_SFIXED32: ('int32_t', 'SFIXED32', 4, False), FieldD.TYPE_SFIXED32: ('int32_t', 'SFIXED32', 4),
FieldD.TYPE_SFIXED64: ('int64_t', 'SFIXED64', 8, False), FieldD.TYPE_SFIXED64: ('int64_t', 'SFIXED64', 8),
FieldD.TYPE_SINT32: ('int32_t', 'SINT32', 5, True), FieldD.TYPE_SINT32: ('int32_t', 'SINT32', 5),
FieldD.TYPE_SINT64: ('int64_t', 'SINT64', 10, True), FieldD.TYPE_SINT64: ('int64_t', 'SINT64', 10),
FieldD.TYPE_UINT32: ('uint32_t', 'UINT32', 5, True), FieldD.TYPE_UINT32: ('uint32_t', 'UINT32', 5),
FieldD.TYPE_UINT64: ('uint64_t', 'UINT64', 10, True) FieldD.TYPE_UINT64: ('uint64_t', 'UINT64', 10)
}
# Integer size overrides (from .proto settings)
intsizes = {
nanopb_pb2.IS_8: 'int8_t',
nanopb_pb2.IS_16: 'int16_t',
nanopb_pb2.IS_32: 'int32_t',
nanopb_pb2.IS_64: 'int64_t',
} }
class Names: class Names:
@@ -171,7 +163,6 @@ class Field:
'''desc is FieldDescriptorProto''' '''desc is FieldDescriptorProto'''
self.tag = desc.number self.tag = desc.number
self.struct_name = struct_name self.struct_name = struct_name
self.union_name = None
self.name = desc.name self.name = desc.name
self.default = None self.default = None
self.max_size = None self.max_size = None
@@ -235,13 +226,7 @@ class Field:
# Decide the C data type to use in the struct. # Decide the C data type to use in the struct.
if datatypes.has_key(desc.type): if datatypes.has_key(desc.type):
self.ctype, self.pbtype, self.enc_size, isa = datatypes[desc.type] self.ctype, self.pbtype, self.enc_size = datatypes[desc.type]
# Override the field size if user wants to use smaller integers
if isa and field_options.int_size != nanopb_pb2.IS_DEFAULT:
self.ctype = intsizes[field_options.int_size]
if desc.type == FieldD.TYPE_UINT32 or desc.type == FieldD.TYPE_UINT64:
self.ctype = 'u' + self.ctype;
elif desc.type == FieldD.TYPE_ENUM: elif desc.type == FieldD.TYPE_ENUM:
self.pbtype = 'ENUM' self.pbtype = 'ENUM'
self.ctype = names_from_type_name(desc.type_name) self.ctype = names_from_type_name(desc.type_name)
@@ -276,7 +261,7 @@ class Field:
result = '' result = ''
if self.allocation == 'POINTER': if self.allocation == 'POINTER':
if self.rules == 'REPEATED': if self.rules == 'REPEATED':
result += ' pb_size_t ' + self.name + '_count;\n' result += ' size_t ' + self.name + '_count;\n'
if self.pbtype == 'MESSAGE': if self.pbtype == 'MESSAGE':
# Use struct definition, so recursive submessages are possible # Use struct definition, so recursive submessages are possible
@@ -292,100 +277,69 @@ class Field:
if self.rules == 'OPTIONAL' and self.allocation == 'STATIC': if self.rules == 'OPTIONAL' and self.allocation == 'STATIC':
result += ' bool has_' + self.name + ';\n' result += ' bool has_' + self.name + ';\n'
elif self.rules == 'REPEATED' and self.allocation == 'STATIC': elif self.rules == 'REPEATED' and self.allocation == 'STATIC':
result += ' pb_size_t ' + self.name + '_count;\n' result += ' size_t ' + self.name + '_count;\n'
result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl) result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl)
return result return result
def types(self): def types(self):
'''Return definitions for any special types this field might need.''' '''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':
result = 'typedef PB_BYTES_ARRAY_T(%d) %s;\n' % (self.max_size, self.ctype) result = 'typedef struct {\n'
result += ' size_t size;\n'
result += ' uint8_t bytes[%d];\n' % self.max_size
result += '} %s;\n' % self.ctype
else: else:
result = '' result = None
return result return result
def get_dependencies(self): def get_initializer(self, null_init):
'''Get list of type names used by this field.''' '''Return literal expression for this field's default value.'''
if self.allocation == 'STATIC':
return [str(self.ctype)]
else:
return []
def get_initializer(self, null_init, inner_init_only = False):
'''Return literal expression for this field's default value.
null_init: If True, initialize to a 0 value instead of default from .proto
inner_init_only: If True, exclude initialization for any count/has fields
'''
inner_init = None
if self.pbtype == 'MESSAGE': if self.pbtype == 'MESSAGE':
if null_init: if null_init:
inner_init = '%s_init_zero' % self.ctype return '%s_init_zero' % self.ctype
else: else:
inner_init = '%s_init_default' % self.ctype return '%s_init_default' % self.ctype
elif self.default is None or null_init:
if self.pbtype == 'STRING':
inner_init = '""'
elif self.pbtype == 'BYTES':
inner_init = '{0, {0}}'
elif self.pbtype == 'ENUM':
inner_init = '(%s)0' % self.ctype
else:
inner_init = '0'
else:
if self.pbtype == 'STRING':
inner_init = self.default.encode('utf-8').encode('string_escape')
inner_init = inner_init.replace('"', '\\"')
inner_init = '"' + inner_init + '"'
elif self.pbtype == 'BYTES':
data = str(self.default).decode('string_escape')
data = ['0x%02x' % ord(c) for c in data]
if len(data) == 0:
inner_init = '{0, {0}}'
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']:
inner_init = str(self.default) + 'ull'
elif self.pbtype in ['SFIXED64', 'INT64']:
inner_init = str(self.default) + 'll'
else:
inner_init = str(self.default)
if inner_init_only: if self.default is None or null_init:
return inner_init if self.pbtype == 'STRING':
return '""'
outer_init = None elif self.pbtype == 'BYTES':
if self.allocation == 'STATIC': return '{0, {0}}'
if self.rules == 'REPEATED': elif self.pbtype == 'ENUM':
outer_init = '0, {' return '(%s)0' % self.ctype
outer_init += ', '.join([inner_init] * self.max_count)
outer_init += '}'
elif self.rules == 'OPTIONAL':
outer_init = 'false, ' + inner_init
else: else:
outer_init = inner_init return '0'
elif self.allocation == 'POINTER':
if self.rules == 'REPEATED': default = str(self.default)
outer_init = '0, NULL'
if self.pbtype == 'STRING':
default = default.encode('utf-8').encode('string_escape')
default = default.replace('"', '\\"')
default = '"' + default + '"'
elif self.pbtype == 'BYTES':
data = default.decode('string_escape')
data = ['0x%02x' % ord(c) for c in data]
if len(data) == 0:
default = '{0, {0}}'
else: else:
outer_init = 'NULL' default = '{%d, {%s}}' % (len(data), ','.join(data))
elif self.allocation == 'CALLBACK': elif self.pbtype in ['FIXED32', 'UINT32']:
if self.pbtype == 'EXTENSION': default += 'u'
outer_init = 'NULL' elif self.pbtype in ['FIXED64', 'UINT64']:
else: default += 'ull'
outer_init = '{{NULL}, NULL}' elif self.pbtype in ['SFIXED64', 'INT64']:
default += 'll'
return outer_init
return default
def default_decl(self, declaration_only = False): def default_decl(self, declaration_only = False):
'''Return definition for this field's default value.''' '''Return definition for this field's default value.'''
if self.default is None: if self.default is None:
return None return None
ctype = self.ctype ctype = self.ctype
default = self.get_initializer(False, True) default = self.get_initializer(False)
array_decl = '' array_decl = ''
if self.pbtype == 'STRING': if self.pbtype == 'STRING':
@@ -410,13 +364,7 @@ class Field:
'''Return the pb_field_t initializer to use in the constant array. '''Return the pb_field_t initializer to use in the constant array.
prev_field_name is the name of the previous field or None. prev_field_name is the name of the previous field or None.
''' '''
result = ' PB_FIELD2(%3d, ' % self.tag
if self.rules == 'ONEOF':
result = ' PB_ONEOF_FIELD(%s, ' % self.union_name
else:
result = ' PB_FIELD('
result += '%3d, ' % self.tag
result += '%-8s, ' % self.pbtype result += '%-8s, ' % self.pbtype
result += '%s, ' % self.rules result += '%s, ' % self.rules
result += '%-8s, ' % self.allocation result += '%-8s, ' % self.allocation
@@ -444,8 +392,6 @@ class Field:
if self.pbtype == 'MESSAGE': if self.pbtype == 'MESSAGE':
if self.rules == 'REPEATED' and self.allocation == 'STATIC': if self.rules == 'REPEATED' and self.allocation == 'STATIC':
return 'pb_membersize(%s, %s[0])' % (self.struct_name, self.name) return 'pb_membersize(%s, %s[0])' % (self.struct_name, self.name)
elif self.rules == 'ONEOF':
return 'pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name)
else: else:
return 'pb_membersize(%s, %s)' % (self.struct_name, self.name) return 'pb_membersize(%s, %s)' % (self.struct_name, self.name)
@@ -520,7 +466,7 @@ class ExtensionRange(Field):
return ' pb_extension_t *extensions;' return ' pb_extension_t *extensions;'
def types(self): def types(self):
return '' return None
def tags(self): def tags(self):
return '' return ''
@@ -555,8 +501,7 @@ class ExtensionField(Field):
msg +=' type of extension fields is currently supported. */\n' msg +=' type of extension fields is currently supported. */\n'
return msg return msg
return ('extern const pb_extension_type_t %s; /* field type: %s */\n' % return 'extern const pb_extension_type_t %s;\n' % self.fullname
(self.fullname, str(self).strip()))
def extension_def(self): def extension_def(self):
'''Definition of the extension type in the .pb.c file''' '''Definition of the extension type in the .pb.c file'''
@@ -577,82 +522,6 @@ class ExtensionField(Field):
return result return result
# ---------------------------------------------------------------------------
# Generation of oneofs (unions)
# ---------------------------------------------------------------------------
class OneOf(Field):
def __init__(self, struct_name, oneof_desc):
self.struct_name = struct_name
self.name = oneof_desc.name
self.ctype = 'union'
self.fields = []
def add_field(self, field):
if field.allocation == 'CALLBACK':
raise Exception("Callback fields inside of oneof are not supported"
+ " (field %s)" % field.name)
field.union_name = self.name
field.rules = 'ONEOF'
self.fields.append(field)
self.fields.sort(key = lambda f: f.tag)
# Sort by the lowest tag number inside union
self.tag = min([f.tag for f in self.fields])
def __cmp__(self, other):
return cmp(self.tag, other.tag)
def __str__(self):
result = ''
if self.fields:
result += ' pb_size_t which_' + self.name + ";\n"
result += ' union {\n'
for f in self.fields:
result += ' ' + str(f).replace('\n', '\n ') + '\n'
result += ' } ' + self.name + ';'
return result
def types(self):
return ''.join([f.types() for f in self.fields])
def get_dependencies(self):
deps = []
for f in self.fields:
deps += f.get_dependencies()
return deps
def get_initializer(self, null_init):
return '0, {' + self.fields[0].get_initializer(null_init) + '}'
def default_decl(self, declaration_only = False):
return None
def tags(self):
return '\n'.join([f.tags() for f in self.fields])
def pb_field_t(self, prev_field_name):
prev_field_name = prev_field_name or self.name
result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields])
return result
def largest_field_value(self):
return max([f.largest_field_value() for f in self.fields])
def encoded_size(self, allmsgs):
largest = EncodedSize(0)
for f in self.fields:
size = f.encoded_size(allmsgs)
if size is None:
return None
elif size.symbols:
return None # Cannot resolve maximum of symbols
elif size.value > largest.value:
largest = size
return largest
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Generation of messages (structures) # Generation of messages (structures)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -662,34 +531,11 @@ class Message:
def __init__(self, names, desc, message_options): def __init__(self, names, desc, message_options):
self.name = names self.name = names
self.fields = [] self.fields = []
self.oneofs = {}
no_unions = []
if hasattr(desc, 'oneof_decl'):
for i, f in enumerate(desc.oneof_decl):
oneof_options = get_nanopb_suboptions(desc, message_options, self.name + f.name)
if oneof_options.no_unions:
no_unions.append(i) # No union, but add fields normally
elif oneof_options.type == nanopb_pb2.FT_IGNORE:
pass # No union and skip fields also
else:
oneof = OneOf(self.name, f)
self.oneofs[i] = oneof
self.fields.append(oneof)
for f in desc.field: for f in desc.field:
field_options = get_nanopb_suboptions(f, message_options, self.name + f.name) field_options = get_nanopb_suboptions(f, message_options, self.name + f.name)
if field_options.type == nanopb_pb2.FT_IGNORE: if field_options.type != nanopb_pb2.FT_IGNORE:
continue self.fields.append(Field(self.name, f, field_options))
field = Field(self.name, f, field_options)
if (hasattr(f, 'oneof_index') and
f.HasField('oneof_index') and
f.oneof_index not in no_unions):
if f.oneof_index in self.oneofs:
self.oneofs[f.oneof_index].add_field(field)
else:
self.fields.append(field)
if len(desc.extension_range) > 0: if len(desc.extension_range) > 0:
field_options = get_nanopb_suboptions(desc, message_options, self.name + 'extensions') field_options = get_nanopb_suboptions(desc, message_options, self.name + 'extensions')
@@ -703,10 +549,7 @@ class Message:
def get_dependencies(self): def get_dependencies(self):
'''Get list of type names that this structure refers to.''' '''Get list of type names that this structure refers to.'''
deps = [] return [str(field.ctype) for field in self.fields]
for f in self.fields:
deps += f.get_dependencies()
return deps
def __str__(self): def __str__(self):
result = 'typedef struct _%s {\n' % self.name result = 'typedef struct _%s {\n' % self.name
@@ -731,15 +574,37 @@ class Message:
return result return result
def types(self): def types(self):
return ''.join([f.types() for f in self.fields]) result = ""
for field in self.fields:
types = field.types()
if types is not None:
result += types + '\n'
return result
def get_initializer(self, null_init): def get_initializer(self, null_init):
if not self.ordered_fields: if not self.ordered_fields:
return '{0}' return '{0}'
parts = [] parts = []
for field in self.ordered_fields: for field in self.ordered_fields:
parts.append(field.get_initializer(null_init)) if field.allocation == 'STATIC':
if field.rules == 'REPEATED':
parts.append('0')
parts.append('{'
+ ', '.join([field.get_initializer(null_init)] * field.max_count)
+ '}')
elif field.rules == 'OPTIONAL':
parts.append('false')
parts.append(field.get_initializer(null_init))
else:
parts.append(field.get_initializer(null_init))
elif field.allocation == 'POINTER':
parts.append('NULL')
elif field.allocation == 'CALLBACK':
if field.pbtype == 'EXTENSION':
parts.append('NULL')
else:
parts.append('{{NULL}, NULL}')
return '{' + ', '.join(parts) + '}' return '{' + ', '.join(parts) + '}'
def default_decl(self, declaration_only = False): def default_decl(self, declaration_only = False):
@@ -750,39 +615,18 @@ class Message:
result += default + '\n' result += default + '\n'
return result return result
def count_required_fields(self):
'''Returns number of required fields inside this message'''
count = 0
for f in self.fields:
if not isinstance(f, OneOf):
if f.rules == 'REQUIRED':
count += 1
return count
def count_all_fields(self):
count = 0
for f in self.fields:
if isinstance(f, OneOf):
count += len(f.fields)
else:
count += 1
return count
def fields_declaration(self): def fields_declaration(self):
result = 'extern const pb_field_t %s_fields[%d];' % (self.name, self.count_all_fields() + 1) result = 'extern const pb_field_t %s_fields[%d];' % (self.name, len(self.fields) + 1)
return result return result
def fields_definition(self): def fields_definition(self):
result = 'const pb_field_t %s_fields[%d] = {\n' % (self.name, self.count_all_fields() + 1) result = 'const pb_field_t %s_fields[%d] = {\n' % (self.name, len(self.fields) + 1)
prev = None prev = None
for field in self.ordered_fields: for field in self.ordered_fields:
result += field.pb_field_t(prev) result += field.pb_field_t(prev)
result += ',\n' result += ',\n'
if isinstance(field, OneOf): prev = field.name
prev = field.name + '.' + field.fields[-1].name
else:
prev = field.name
result += ' PB_LAST_FIELD\n};' result += ' PB_LAST_FIELD\n};'
return result return result
@@ -927,8 +771,8 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
symbol = make_identifier(headername) symbol = make_identifier(headername)
yield '#ifndef PB_%s_INCLUDED\n' % symbol yield '#ifndef _PB_%s_\n' % symbol
yield '#define PB_%s_INCLUDED\n' % symbol yield '#define _PB_%s_\n' % symbol
try: try:
yield options.libformat % ('pb.h') yield options.libformat % ('pb.h')
except TypeError: except TypeError:
@@ -941,11 +785,6 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio
yield options.genformat % (noext + options.extension + '.h') yield options.genformat % (noext + options.extension + '.h')
yield '\n' yield '\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'
yield '\n'
yield '#ifdef __cplusplus\n' yield '#ifdef __cplusplus\n'
yield 'extern "C" {\n' yield 'extern "C" {\n'
yield '#endif\n\n' yield '#endif\n\n'
@@ -1018,11 +857,6 @@ def generate_source(headername, enums, messages, extensions, options):
yield options.genformat % (headername) yield options.genformat % (headername)
yield '\n' yield '\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'
yield '\n'
for msg in messages: for msg in messages:
yield msg.default_decl(False) yield msg.default_decl(False)
@@ -1036,8 +870,9 @@ def generate_source(headername, enums, messages, extensions, options):
# Add checks for numeric limits # Add checks for numeric limits
if messages: if messages:
largest_msg = max(messages, key = lambda m: m.count_required_fields()) count_required_fields = lambda m: len([f for f in msg.fields if f.rules == 'REQUIRED'])
largest_count = largest_msg.count_required_fields() largest_msg = max(messages, key = count_required_fields)
largest_count = count_required_fields(largest_msg)
if largest_count > 64: if largest_count > 64:
yield '\n/* Check that missing required fields will be properly detected */\n' yield '\n/* Check that missing required fields will be properly detected */\n'
yield '#if PB_MAX_REQUIRED_FIELDS < %d\n' % largest_count yield '#if PB_MAX_REQUIRED_FIELDS < %d\n' % largest_count
@@ -1076,7 +911,7 @@ def generate_source(headername, enums, messages, extensions, options):
yield ' * numbers or field sizes that are larger than what can fit in 8 or 16 bit\n' yield ' * numbers or field sizes that are larger than what can fit in 8 or 16 bit\n'
yield ' * field descriptors.\n' yield ' * field descriptors.\n'
yield ' */\n' yield ' */\n'
yield 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield '#endif\n\n' yield '#endif\n\n'
if worst < 65536: if worst < 65536:
@@ -1093,7 +928,7 @@ def generate_source(headername, enums, messages, extensions, options):
yield ' * numbers or field sizes that are larger than what can fit in the default\n' yield ' * numbers or field sizes that are larger than what can fit in the default\n'
yield ' * 8 bit descriptors.\n' yield ' * 8 bit descriptors.\n'
yield ' */\n' yield ' */\n'
yield 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield '#endif\n\n' yield '#endif\n\n'
# Add check for sizeof(double) # Add check for sizeof(double)
@@ -1109,7 +944,7 @@ def generate_source(headername, enums, messages, extensions, options):
yield ' * These are not directly supported by nanopb, but see example_avr_double.\n' yield ' * These are not directly supported by nanopb, but see example_avr_double.\n'
yield ' * To get rid of this error, remove any double fields from your .proto.\n' yield ' * To get rid of this error, remove any double fields from your .proto.\n'
yield ' */\n' yield ' */\n'
yield 'PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n' yield 'STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n'
yield '\n' yield '\n'

View File

@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/ // http://code.google.com/p/protobuf/
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@@ -37,7 +37,6 @@
// without any other information (e.g. without reading its imports). // without any other information (e.g. without reading its imports).
syntax = "proto2";
package google.protobuf; package google.protobuf;
option java_package = "com.google.protobuf"; option java_package = "com.google.protobuf";
@@ -75,14 +74,10 @@ message FileDescriptorProto {
optional FileOptions options = 8; optional FileOptions options = 8;
// This field contains optional information about the original source code. // This field contains optional information about the original source code.
// You may safely remove this entire field without harming runtime // You may safely remove this entire field whithout harming runtime
// functionality of the descriptors -- the information is needed only by // functionality of the descriptors -- the information is needed only by
// development tools. // development tools.
optional SourceCodeInfo source_code_info = 9; optional SourceCodeInfo source_code_info = 9;
// The syntax of the proto file.
// The supported values are "proto2" and "proto3".
optional string syntax = 12;
} }
// Describes a message type. // Describes a message type.
@@ -101,8 +96,6 @@ message DescriptorProto {
} }
repeated ExtensionRange extension_range = 5; repeated ExtensionRange extension_range = 5;
repeated OneofDescriptorProto oneof_decl = 8;
optional MessageOptions options = 7; optional MessageOptions options = 7;
} }
@@ -150,7 +143,7 @@ message FieldDescriptorProto {
optional Label label = 4; optional Label label = 4;
// If type_name is set, this need not be set. If both this and type_name // If type_name is set, this need not be set. If both this and type_name
// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. // are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
optional Type type = 5; optional Type type = 5;
// For message and enum types, this is the name of the type. If the name // For message and enum types, this is the name of the type. If the name
@@ -171,20 +164,9 @@ message FieldDescriptorProto {
// TODO(kenton): Base-64 encode? // TODO(kenton): Base-64 encode?
optional string default_value = 7; optional string default_value = 7;
// If set, gives the index of a oneof in the containing type's oneof_decl
// list. This field is a member of that oneof. Extensions of a oneof should
// not set this since the oneof to which they belong will be inferred based
// on the extension range containing the extension's field number.
optional int32 oneof_index = 9;
optional FieldOptions options = 8; optional FieldOptions options = 8;
} }
// Describes a oneof.
message OneofDescriptorProto {
optional string name = 1;
}
// Describes an enum type. // Describes an enum type.
message EnumDescriptorProto { message EnumDescriptorProto {
optional string name = 1; optional string name = 1;
@@ -220,11 +202,6 @@ message MethodDescriptorProto {
optional string output_type = 3; optional string output_type = 3;
optional MethodOptions options = 4; optional MethodOptions options = 4;
// Identifies if client streams multiple client messages
optional bool client_streaming = 5 [default=false];
// Identifies if server streams multiple server messages
optional bool server_streaming = 6 [default=false];
} }
@@ -256,7 +233,7 @@ message MethodDescriptorProto {
// number. You can declare multiple options with only one extension number by // number. You can declare multiple options with only one extension number by
// putting them in a sub-message. See the Custom Options section of the docs // putting them in a sub-message. See the Custom Options section of the docs
// for examples: // for examples:
// https://developers.google.com/protocol-buffers/docs/proto#options // http://code.google.com/apis/protocolbuffers/docs/proto.html#options
// If this turns out to be popular, a web service will be set up // If this turns out to be popular, a web service will be set up
// to automatically assign option numbers. // to automatically assign option numbers.
@@ -286,26 +263,11 @@ message FileOptions {
optional bool java_multiple_files = 10 [default=false]; optional bool java_multiple_files = 10 [default=false];
// If set true, then the Java code generator will generate equals() and // If set true, then the Java code generator will generate equals() and
// hashCode() methods for all messages defined in the .proto file. // hashCode() methods for all messages defined in the .proto file. This is
// - In the full runtime, this is purely a speed optimization, as the // purely a speed optimization, as the AbstractMessage base class includes
// AbstractMessage base class includes reflection-based implementations of // reflection-based implementations of these methods.
// these methods.
//- In the lite runtime, setting this option changes the semantics of
// equals() and hashCode() to more closely match those of the full runtime;
// the generated methods compute their results based on field values rather
// than object identity. (Implementations should not assume that hashcodes
// will be consistent across runtimes or versions of the protocol compiler.)
optional bool java_generate_equals_and_hash = 20 [default=false]; optional bool java_generate_equals_and_hash = 20 [default=false];
// If set true, then the Java2 code generator will generate code that
// throws an exception whenever an attempt is made to assign a non-UTF-8
// byte sequence to a string field.
// Message reflection will do the same.
// However, an extension field still accepts non-UTF-8 byte sequences.
// This option has no effect on when used with the lite runtime.
optional bool java_string_check_utf8 = 27 [default=false];
// Generated classes can be optimized for speed or code size. // Generated classes can be optimized for speed or code size.
enum OptimizeMode { enum OptimizeMode {
SPEED = 1; // Generate complete code for parsing, serialization, SPEED = 1; // Generate complete code for parsing, serialization,
@@ -316,10 +278,7 @@ message FileOptions {
optional OptimizeMode optimize_for = 9 [default=SPEED]; optional OptimizeMode optimize_for = 9 [default=SPEED];
// Sets the Go package where structs generated from this .proto will be // Sets the Go package where structs generated from this .proto will be
// placed. If omitted, the Go package will be derived from the following: // placed. There is no default.
// - The basename of the package import path, if provided.
// - Otherwise, the package statement in the .proto file, if present.
// - Otherwise, the basename of the .proto file, without extension.
optional string go_package = 11; optional string go_package = 11;
@@ -328,7 +287,7 @@ message FileOptions {
// are not specific to any particular RPC system. They are generated by the // are not specific to any particular RPC system. They are generated by the
// main code generators in each language (without additional plugins). // main code generators in each language (without additional plugins).
// Generic services were the only kind of service generation supported by // Generic services were the only kind of service generation supported by
// early versions of google.protobuf. // early versions of proto2.
// //
// Generic services are now considered deprecated in favor of using plugins // Generic services are now considered deprecated in favor of using plugins
// that generate code specific to your particular RPC system. Therefore, // that generate code specific to your particular RPC system. Therefore,
@@ -338,18 +297,6 @@ message FileOptions {
optional bool java_generic_services = 17 [default=false]; optional bool java_generic_services = 17 [default=false];
optional bool py_generic_services = 18 [default=false]; optional bool py_generic_services = 18 [default=false];
// Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for everything in the file, or it will be completely ignored; in the very
// least, this is a formalization for deprecating files.
optional bool deprecated = 23 [default=false];
// Enables the use of arenas for the proto messages in this file. This applies
// only to generated classes for C++.
optional bool cc_enable_arenas = 31 [default=false];
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;
@@ -383,35 +330,6 @@ message MessageOptions {
// from proto1 easier; new code should avoid fields named "descriptor". // from proto1 easier; new code should avoid fields named "descriptor".
optional bool no_standard_descriptor_accessor = 2 [default=false]; optional bool no_standard_descriptor_accessor = 2 [default=false];
// Is this message deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the message, or it will be completely ignored; in the very least,
// this is a formalization for deprecating messages.
optional bool deprecated = 3 [default=false];
// Whether the message is an automatically generated map entry type for the
// maps field.
//
// For maps fields:
// map<KeyType, ValueType> map_field = 1;
// The parsed descriptor looks like:
// message MapFieldEntry {
// option map_entry = true;
// optional KeyType key = 1;
// optional ValueType value = 2;
// }
// repeated MapFieldEntry map_field = 1;
//
// Implementations may choose not to generate the map_entry=true message, but
// use a native map in the target language to hold the keys and values.
// The reflection APIs in such implementions still need to work as
// if the field is a repeated message field.
//
// NOTE: Do not set the option in .proto files. Always use the maps syntax
// instead. The option should only be implicitly set by the proto compiler
// parser.
optional bool map_entry = 7;
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;
@@ -477,11 +395,23 @@ message FieldOptions {
// is a formalization for deprecating fields. // is a formalization for deprecating fields.
optional bool deprecated = 3 [default=false]; optional bool deprecated = 3 [default=false];
// EXPERIMENTAL. DO NOT USE.
// For "map" fields, the name of the field in the enclosed type that
// is the key for this map. For example, suppose we have:
// message Item {
// required string name = 1;
// required string value = 2;
// }
// message Config {
// repeated Item items = 1 [experimental_map_key="name"];
// }
// In this situation, the map key for Item will be set to "name".
// TODO: Fully-implement this, then remove the "experimental_" prefix.
optional string experimental_map_key = 9;
// For Google-internal migration only. Do not use. // For Google-internal migration only. Do not use.
optional bool weak = 10 [default=false]; optional bool weak = 10 [default=false];
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;
@@ -491,15 +421,9 @@ message FieldOptions {
message EnumOptions { message EnumOptions {
// Set this option to true to allow mapping different tag names to the same // Set this option to false to disallow mapping different tag names to a same
// value. // value.
optional bool allow_alias = 2; optional bool allow_alias = 2 [default=true];
// Is this enum deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the enum, or it will be completely ignored; in the very least, this
// is a formalization for deprecating enums.
optional bool deprecated = 3 [default=false];
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;
@@ -509,12 +433,6 @@ message EnumOptions {
} }
message EnumValueOptions { message EnumValueOptions {
// Is this enum value deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the enum value, or it will be completely ignored; in the very least,
// this is a formalization for deprecating enum values.
optional bool deprecated = 1 [default=false];
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;
@@ -529,12 +447,6 @@ message ServiceOptions {
// we were already using them long before we decided to release Protocol // we were already using them long before we decided to release Protocol
// Buffers. // Buffers.
// Is this service deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the service, or it will be completely ignored; in the very least,
// this is a formalization for deprecating services.
optional bool deprecated = 33 [default=false];
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;
@@ -549,12 +461,6 @@ message MethodOptions {
// we were already using them long before we decided to release Protocol // we were already using them long before we decided to release Protocol
// Buffers. // Buffers.
// Is this method deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the method, or it will be completely ignored; in the very least,
// this is a formalization for deprecating methods.
optional bool deprecated = 33 [default=false];
// The parser stores options it doesn't recognize here. See above. // The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999; repeated UninterpretedOption uninterpreted_option = 999;

View File

@@ -5,7 +5,6 @@
// These are used by nanopb to generate statically allocable structures // These are used by nanopb to generate statically allocable structures
// for memory-limited environments. // for memory-limited environments.
syntax = "proto2";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
option java_package = "fi.kapsi.koti.jpa.nanopb"; option java_package = "fi.kapsi.koti.jpa.nanopb";
@@ -18,14 +17,6 @@ enum FieldType {
FT_IGNORE = 3; // Ignore the field completely. FT_IGNORE = 3; // Ignore the field completely.
} }
enum IntSize {
IS_DEFAULT = 0; // Default, 32/64bit based on type in .proto
IS_8 = 8;
IS_16 = 16;
IS_32 = 32;
IS_64 = 64;
}
// This is the inner options message, which basically defines options for // This is the inner options message, which basically defines options for
// a field. When it is used in message or file scope, it applies to all // a field. When it is used in message or file scope, it applies to all
// fields. // fields.
@@ -36,10 +27,6 @@ message NanoPBOptions {
// Allocated number of entries in arrays ('repeated' fields) // Allocated number of entries in arrays ('repeated' fields)
optional int32 max_count = 2; optional int32 max_count = 2;
// Size of integer fields. Can save some memory if you don't need
// full 32 bits for the value.
optional IntSize int_size = 7 [default = IS_DEFAULT];
// Force type of field (callback or static allocation) // Force type of field (callback or static allocation)
optional FieldType type = 3 [default = FT_DEFAULT]; optional FieldType type = 3 [default = FT_DEFAULT];
@@ -53,9 +40,6 @@ message NanoPBOptions {
// Skip this message // Skip this message
optional bool skip_message = 6 [default = false]; optional bool skip_message = 6 [default = false];
// Generate oneof fields as normal optional fields instead of union.
optional bool no_unions = 8 [default = false];
} }
// Extensions to protoc 'Descriptor' type in order to define options // Extensions to protoc 'Descriptor' type in order to define options

View File

@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/ // http://code.google.com/p/protobuf/
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@@ -44,10 +44,7 @@
// plugin should be named "protoc-gen-$NAME", and will then be used when the // plugin should be named "protoc-gen-$NAME", and will then be used when the
// flag "--${NAME}_out" is passed to protoc. // flag "--${NAME}_out" is passed to protoc.
syntax = "proto2";
package google.protobuf.compiler; package google.protobuf.compiler;
option java_package = "com.google.protobuf.compiler";
option java_outer_classname = "PluginProtos";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";

151
pb.h
View File

@@ -2,8 +2,8 @@
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h. * stuff. For the high-level interface, see pb_encode.h and pb_decode.h.
*/ */
#ifndef PB_H_INCLUDED #ifndef _PB_H_
#define PB_H_INCLUDED #define _PB_H_
/***************************************************************** /*****************************************************************
* Nanopb compilation time options. You can change these here by * * Nanopb compilation time options. You can change these here by *
@@ -17,10 +17,6 @@
* stores the most-significant byte first. */ * stores the most-significant byte first. */
/* #define __BIG_ENDIAN__ 1 */ /* #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 */
/* Increase the number of required fields that are tracked. /* Increase the number of required fields that are tracked.
* A compiler warning will tell if you need this. */ * A compiler warning will tell if you need this. */
/* #define PB_MAX_REQUIRED_FIELDS 256 */ /* #define PB_MAX_REQUIRED_FIELDS 256 */
@@ -50,7 +46,7 @@
/* Version of the nanopb library. Just in case you want to check it in /* Version of the nanopb library. Just in case you want to check it in
* your own program. */ * your own program. */
#define NANOPB_VERSION nanopb-0.3.2 #define NANOPB_VERSION nanopb-0.2.9.1
/* Include all the system headers needed by nanopb. You will need the /* Include all the system headers needed by nanopb. You will need the
* definitions of the following: * definitions of the following:
@@ -79,12 +75,7 @@
/* Macro for defining packed structures (compiler dependent). /* Macro for defining packed structures (compiler dependent).
* This just reduces memory requirements, but is not required. * This just reduces memory requirements, but is not required.
*/ */
#if defined(PB_NO_PACKED_STRUCTS) #if defined(__GNUC__) || defined(__clang__)
/* Disable struct packing */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#elif defined(__GNUC__) || defined(__clang__)
/* For GCC and clang */ /* For GCC and clang */
# define PB_PACKED_STRUCT_START # define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END # define PB_PACKED_STRUCT_END
@@ -107,27 +98,23 @@
#endif #endif
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ /* Handly macro for suppressing unreferenced-parameter compiler warnings. */
#ifndef PB_UNUSED #ifndef UNUSED
#define PB_UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
#endif #endif
/* Compile-time assertion, used for checking compatible compilation options. /* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use * If this does not work properly on your compiler, use #define STATIC_ASSERT
* #define PB_NO_STATIC_ASSERT to disable it. * to disable it.
* *
* But before doing that, check carefully the error message / place where it * But before doing that, check carefully the error message / place where it
* comes from to see if the error has a real cause. Unfortunately the error * comes from to see if the error has a real cause. Unfortunately the error
* message is not always very clear to read, but you can see the reason better * message is not always very clear to read, but you can see the reason better
* in the place where the PB_STATIC_ASSERT macro was called. * in the place where the STATIC_ASSERT macro was called.
*/ */
#ifndef PB_NO_STATIC_ASSERT #ifndef STATIC_ASSERT
#ifndef PB_STATIC_ASSERT #define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; #define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) #define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER
#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER
#endif
#else
#define PB_STATIC_ASSERT(COND,MSG)
#endif #endif
/* Number of required fields to keep track of. */ /* Number of required fields to keep track of. */
@@ -183,7 +170,6 @@ typedef uint8_t pb_type_t;
#define PB_HTYPE_REQUIRED 0x00 #define PB_HTYPE_REQUIRED 0x00
#define PB_HTYPE_OPTIONAL 0x10 #define PB_HTYPE_OPTIONAL 0x10
#define PB_HTYPE_REPEATED 0x20 #define PB_HTYPE_REPEATED 0x20
#define PB_HTYPE_ONEOF 0x30
#define PB_HTYPE_MASK 0x30 #define PB_HTYPE_MASK 0x30
/**** Field allocation types ****/ /**** Field allocation types ****/
@@ -201,15 +187,12 @@ typedef uint8_t pb_type_t;
* and array counts. * and array counts.
*/ */
#if defined(PB_FIELD_32BIT) #if defined(PB_FIELD_32BIT)
#define PB_SIZE_MAX ((uint32_t)-1)
typedef uint32_t pb_size_t; typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t; typedef int32_t pb_ssize_t;
#elif defined(PB_FIELD_16BIT) #elif defined(PB_FIELD_16BIT)
#define PB_SIZE_MAX ((uint16_t)-1)
typedef uint16_t pb_size_t; typedef uint16_t pb_size_t;
typedef int16_t pb_ssize_t; typedef int16_t pb_ssize_t;
#else #else
#define PB_SIZE_MAX ((uint8_t)-1)
typedef uint8_t pb_size_t; typedef uint8_t pb_size_t;
typedef int8_t pb_ssize_t; typedef int8_t pb_ssize_t;
#endif #endif
@@ -223,8 +206,8 @@ typedef uint8_t pb_type_t;
* PB_FIELD_32BIT. * PB_FIELD_32BIT.
*/ */
PB_PACKED_STRUCT_START PB_PACKED_STRUCT_START
typedef struct pb_field_s pb_field_t; typedef struct _pb_field_t pb_field_t;
struct pb_field_s { struct _pb_field_t {
pb_size_t tag; pb_size_t tag;
pb_type_t type; pb_type_t type;
pb_size_t data_offset; /* Offset of field data, relative to previous field. */ pb_size_t data_offset; /* Offset of field data, relative to previous field. */
@@ -245,27 +228,27 @@ PB_PACKED_STRUCT_END
* If you get errors here, it probably means that your stdint.h is not * If you get errors here, it probably means that your stdint.h is not
* correct for your platform. * correct for your platform.
*/ */
PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
/* This structure is used for 'bytes' arrays. /* This structure is used for 'bytes' arrays.
* It has the number of bytes in the beginning, and after that an array. * 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. * 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 { size_t size; uint8_t bytes[n]; }
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) #define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
struct pb_bytes_array_s { struct _pb_bytes_array_t {
pb_size_t size; size_t size;
uint8_t bytes[1]; uint8_t bytes[1];
}; };
typedef struct pb_bytes_array_s pb_bytes_array_t; typedef struct _pb_bytes_array_t pb_bytes_array_t;
/* This structure is used for giving the callback function. /* This structure is used for giving the callback function.
* It is stored in the message structure and filled in by the method that * It is stored in the message structure and filled in by the method that
@@ -285,10 +268,10 @@ typedef struct pb_bytes_array_s pb_bytes_array_t;
* *
* The callback can be null if you want to skip a field. * The callback can be null if you want to skip a field.
*/ */
typedef struct pb_istream_s pb_istream_t; typedef struct _pb_istream_t pb_istream_t;
typedef struct pb_ostream_s pb_ostream_t; typedef struct _pb_ostream_t pb_ostream_t;
typedef struct pb_callback_s pb_callback_t; typedef struct _pb_callback_t pb_callback_t;
struct pb_callback_s { struct _pb_callback_t {
#ifdef PB_OLD_CALLBACK_STYLE #ifdef PB_OLD_CALLBACK_STYLE
/* Deprecated since nanopb-0.2.1 */ /* Deprecated since nanopb-0.2.1 */
union { union {
@@ -321,9 +304,9 @@ typedef enum {
* if you want to catch all unknown fields, you can also create a custom * if you want to catch all unknown fields, you can also create a custom
* pb_extension_type_t with your own callback. * pb_extension_type_t with your own callback.
*/ */
typedef struct pb_extension_type_s pb_extension_type_t; typedef struct _pb_extension_type_t pb_extension_type_t;
typedef struct pb_extension_s pb_extension_t; typedef struct _pb_extension_t pb_extension_t;
struct pb_extension_type_s { struct _pb_extension_type_t {
/* Called for each unknown field in the message. /* Called for each unknown field in the message.
* If you handle the field, read off all of its data and return true. * If you handle the field, read off all of its data and return true.
* If you do not handle the field, do not read anything and return true. * If you do not handle the field, do not read anything and return true.
@@ -345,7 +328,7 @@ struct pb_extension_type_s {
const void *arg; const void *arg;
}; };
struct pb_extension_s { struct _pb_extension_t {
/* Type describing the extension field. Usually you'll initialize /* Type describing the extension field. Usually you'll initialize
* this to a pointer to the automatically generated structure. */ * this to a pointer to the automatically generated structure. */
const pb_extension_type_t *type; const pb_extension_type_t *type;
@@ -375,9 +358,6 @@ struct pb_extension_s {
# endif # endif
#endif #endif
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */
#define PB_PROTO_HEADER_VERSION 30
/* These macros are used to declare pb_field_t's in the constant array. */ /* These macros are used to declare pb_field_t's in the constant array. */
/* Size of a structure member, in bytes. */ /* Size of a structure member, in bytes. */
#define pb_membersize(st, m) (sizeof ((st*)0)->m) #define pb_membersize(st, m) (sizeof ((st*)0)->m)
@@ -457,11 +437,9 @@ struct pb_extension_s {
0, \ 0, \
pb_membersize(st, m), 0, ptr} pb_membersize(st, m), 0, ptr}
#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr)
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ #define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
0, 0, pb_membersize(st, m), 0, ptr}
/* The mapping from protobuf types to LTYPEs is done using these macros. */ /* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT #define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT
@@ -491,56 +469,51 @@ struct pb_extension_s {
* SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
* - Field rules: REQUIRED, OPTIONAL or REPEATED * - Field rules: REQUIRED, OPTIONAL or REPEATED
* - Allocation: STATIC or CALLBACK * - Allocation: STATIC or CALLBACK
* - Placement: FIRST or OTHER, depending on if this is the first field in structure.
* - Message name * - Message name
* - Field name * - Field name
* - Previous field name (or field name again for first field) * - Previous field name (or field name again for first field)
* - Pointer to default value or submsg fields. * - Pointer to default value or submsg fields.
*/ */
#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ #define PB_FIELD(tag, type, rules, allocation, message, field, prevfield, ptr) \
PB_ ## rules ## _ ## allocation(tag, message, field, \ PB_ ## rules ## _ ## allocation(tag, message, field, \
PB_DATAOFFSET_CHOOSE(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* This is a new version of the macro used by nanopb generator from
* version 0.2.3 onwards. It avoids the use of a ternary expression in
* the initialization, which confused some compilers.
*
* - Placement: FIRST or OTHER, depending on if this is the first field in structure.
*
*/
#define PB_FIELD2(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ ## rules ## _ ## allocation(tag, message, field, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \ PB_DATAOFFSET_ ## placement(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr) PB_LTYPE_MAP_ ## type, ptr)
/* Field description for oneof fields. This requires taking into account the
* union name also, that's why a separate set of macros is needed.
*/
#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, u.m), \
pb_membersize(st, u.m), 0, ptr}
#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, u.m), \
pb_membersize(st, u.m[0]), 0, ptr}
#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ ## rules ## _ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* These macros are used for giving out error messages. /* These macros are used for giving out error messages.
* They are mostly a debugging aid; the main error information * They are mostly a debugging aid; the main error information
* is the true/false return value from functions. * is the true/false return value from functions.
* Some code space can be saved by disabling the error * Some code space can be saved by disabling the error
* messages if not used. * messages if not used.
*
* PB_SET_ERROR() sets the error message if none has been set yet.
* msg must be a constant string literal.
* PB_GET_ERROR() always returns a pointer to a string.
* PB_RETURN_ERROR() sets the error and returns false from current
* function.
*/ */
#ifdef PB_NO_ERRMSG #ifdef PB_NO_ERRMSG
#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) #define PB_RETURN_ERROR(stream,msg) \
do {\
UNUSED(stream); \
return false; \
} while(0)
#define PB_GET_ERROR(stream) "(errmsg disabled)" #define PB_GET_ERROR(stream) "(errmsg disabled)"
#else #else
#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) #define PB_RETURN_ERROR(stream,msg) \
do {\
if ((stream)->errmsg == NULL) \
(stream)->errmsg = (msg); \
return false; \
} while(0)
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") #define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
#endif #endif
#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
#endif #endif

View File

@@ -1,97 +0,0 @@
/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
*
* 2014 Petteri Aimonen <jpa@kapsi.fi>
*/
#include "pb_common.h"
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct)
{
iter->start = fields;
iter->pos = fields;
iter->required_field_index = 0;
iter->dest_struct = dest_struct;
iter->pData = (char*)dest_struct + iter->pos->data_offset;
iter->pSize = (char*)iter->pData + iter->pos->size_offset;
return (iter->pos->tag != 0);
}
bool pb_field_iter_next(pb_field_iter_t *iter)
{
const pb_field_t *prev_field = iter->pos;
if (prev_field->tag == 0)
{
/* Handle empty message types, where the first field is already the terminator.
* In other cases, the iter->pos never points to the terminator. */
return false;
}
iter->pos++;
if (iter->pos->tag == 0)
{
/* Wrapped back to beginning, reinitialize */
(void)pb_field_iter_begin(iter, iter->start, iter->dest_struct);
return false;
}
else
{
/* Increment the pointers based on previous field size */
size_t prev_size = prev_field->data_size;
if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF &&
PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF)
{
/* Don't advance pointers inside unions */
prev_size = 0;
iter->pData = (char*)iter->pData - prev_field->data_offset;
}
else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC &&
PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED)
{
/* In static arrays, the data_size tells the size of a single entry and
* array_size is the number of entries */
prev_size *= prev_field->array_size;
}
else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER)
{
/* Pointer fields always have a constant size in the main structure.
* The data_size only applies to the dynamically allocated area. */
prev_size = sizeof(void*);
}
if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED)
{
/* Count the required fields, in order to check their presence in the
* decoder. */
iter->required_field_index++;
}
iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset;
iter->pSize = (char*)iter->pData + iter->pos->size_offset;
return true;
}
}
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
{
const pb_field_t *start = iter->pos;
do {
if (iter->pos->tag == tag &&
PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION)
{
/* Found the wanted field */
return true;
}
(void)pb_field_iter_next(iter);
} while (iter->pos != start);
/* Searched all the way back to start, and found nothing. */
return false;
}

View File

@@ -1,42 +0,0 @@
/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c.
* These functions are rarely needed by applications directly.
*/
#ifndef PB_COMMON_H_INCLUDED
#define PB_COMMON_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Iterator for pb_field_t list */
struct pb_field_iter_s {
const pb_field_t *start; /* Start of the pb_field_t array */
const pb_field_t *pos; /* Current position of the iterator */
unsigned required_field_index; /* Zero-based index that counts only the required fields */
void *dest_struct; /* Pointer to start of the structure */
void *pData; /* Pointer to current field value */
void *pSize; /* Pointer to count/has field */
};
typedef struct pb_field_iter_s pb_field_iter_t;
/* Initialize the field iterator structure to beginning.
* Returns false if the message type is empty. */
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct);
/* Advance the iterator to the next field.
* Returns false when the iterator wraps back to the first field. */
bool pb_field_iter_next(pb_field_iter_t *iter);
/* Advance the iterator until it points at a field with the given tag.
* Returns false if no such field exists. */
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -15,25 +15,36 @@
#include "pb.h" #include "pb.h"
#include "pb_decode.h" #include "pb_decode.h"
#include "pb_common.h"
/************************************** /**************************************
* Declarations internal to this file * * Declarations internal to this file *
**************************************/ **************************************/
/* Iterator for pb_field_t list */
typedef struct {
const pb_field_t *start; /* Start of the pb_field_t array */
const pb_field_t *pos; /* Current position of the iterator */
unsigned field_index; /* Zero-based index of the field. */
unsigned required_field_index; /* Zero-based index that counts only the required fields */
void *dest_struct; /* Pointer to the destination structure to decode to */
void *pData; /* Pointer where to store current field value */
void *pSize; /* Pointer where to store the size of current array field */
} pb_field_iterator_t;
typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; 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, uint8_t *buf, size_t count);
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); 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, uint8_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 void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); static bool pb_field_next(pb_field_iterator_t *iter);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag);
static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
static bool checkreturn find_extension_field(pb_field_iter_t *iter); static bool checkreturn find_extension_field(pb_field_iterator_t *iter);
static void pb_field_set_to_default(pb_field_iter_t *iter);
static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);
static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);
@@ -48,8 +59,7 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream);
#ifdef PB_ENABLE_MALLOC #ifdef PB_ENABLE_MALLOC
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);
static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); static void pb_release_single_field(const pb_field_iterator_t *iter);
static void pb_release_single_field(const pb_field_iter_t *iter);
#endif #endif
/* --- Function pointers to field decoders --- /* --- Function pointers to field decoders ---
@@ -333,11 +343,75 @@ void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
#endif #endif
} }
static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct)
{
iter->start = iter->pos = fields;
iter->field_index = 0;
iter->required_field_index = 0;
iter->pData = (char*)dest_struct + iter->pos->data_offset;
iter->pSize = (char*)iter->pData + iter->pos->size_offset;
iter->dest_struct = dest_struct;
}
static bool pb_field_next(pb_field_iterator_t *iter)
{
bool notwrapped = true;
size_t prev_size = iter->pos->data_size;
if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC &&
PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED)
{
prev_size *= iter->pos->array_size;
}
else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER)
{
prev_size = sizeof(void*);
}
if (iter->pos->tag == 0)
return false; /* Only happens with empty message types */
if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED)
iter->required_field_index++;
iter->pos++;
iter->field_index++;
if (iter->pos->tag == 0)
{
iter->pos = iter->start;
iter->field_index = 0;
iter->required_field_index = 0;
iter->pData = iter->dest_struct;
prev_size = 0;
notwrapped = false;
}
iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset;
iter->pSize = (char*)iter->pData + iter->pos->size_offset;
return notwrapped;
}
static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag)
{
unsigned start = iter->field_index;
do {
if (iter->pos->tag == tag &&
PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION)
{
return true;
}
(void)pb_field_next(iter);
} while (iter->field_index != start);
return false;
}
/************************* /*************************
* Decode a single field * * Decode a single field *
*************************/ *************************/
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_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{ {
pb_type_t type; pb_type_t type;
pb_decoder_t func; pb_decoder_t func;
@@ -360,7 +434,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
{ {
/* Packed array */ /* Packed array */
bool status = true; bool status = true;
pb_size_t *size = (pb_size_t*)iter->pSize; size_t *size = (size_t*)iter->pSize;
pb_istream_t substream; pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream)) if (!pb_make_string_substream(stream, &substream))
return false; return false;
@@ -385,7 +459,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
else else
{ {
/* Repeated field */ /* Repeated field */
pb_size_t *size = (pb_size_t*)iter->pSize; size_t *size = (size_t*)iter->pSize;
void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
if (*size >= iter->pos->array_size) if (*size >= iter->pos->array_size)
PB_RETURN_ERROR(stream, "array overflow"); PB_RETURN_ERROR(stream, "array overflow");
@@ -394,10 +468,6 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
return func(stream, iter->pos, pItem); return func(stream, iter->pos, pItem);
} }
case PB_HTYPE_ONEOF:
*(pb_size_t*)iter->pSize = iter->pos->tag;
return func(stream, iter->pos, iter->pData);
default: default:
PB_RETURN_ERROR(stream, "invalid field type"); PB_RETURN_ERROR(stream, "invalid field type");
} }
@@ -444,7 +514,7 @@ static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t
} }
/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ /* Clear a newly allocated item in case it contains a pointer, or is a submessage. */
static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter)
{ {
if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING ||
PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES)
@@ -458,11 +528,11 @@ static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter)
} }
#endif #endif
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{ {
#ifndef PB_ENABLE_MALLOC #ifndef PB_ENABLE_MALLOC
PB_UNUSED(wire_type); UNUSED(wire_type);
PB_UNUSED(iter); UNUSED(iter);
PB_RETURN_ERROR(stream, "no malloc support"); PB_RETURN_ERROR(stream, "no malloc support");
#else #else
pb_type_t type; pb_type_t type;
@@ -475,7 +545,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
{ {
case PB_HTYPE_REQUIRED: case PB_HTYPE_REQUIRED:
case PB_HTYPE_OPTIONAL: case PB_HTYPE_OPTIONAL:
case PB_HTYPE_ONEOF:
if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE &&
*(void**)iter->pData != NULL) *(void**)iter->pData != NULL)
{ {
@@ -483,11 +552,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
pb_release_single_field(iter); pb_release_single_field(iter);
} }
if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
*(pb_size_t*)iter->pSize = iter->pos->tag;
}
if (PB_LTYPE(type) == PB_LTYPE_STRING || if (PB_LTYPE(type) == PB_LTYPE_STRING ||
PB_LTYPE(type) == PB_LTYPE_BYTES) PB_LTYPE(type) == PB_LTYPE_BYTES)
{ {
@@ -508,7 +572,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
{ {
/* Packed array, multiple items come in at once. */ /* Packed array, multiple items come in at once. */
bool status = true; bool status = true;
pb_size_t *size = (pb_size_t*)iter->pSize; size_t *size = (size_t*)iter->pSize;
size_t allocated_size = *size; size_t allocated_size = *size;
void *pItem; void *pItem;
pb_istream_t substream; pb_istream_t substream;
@@ -518,7 +582,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
while (substream.bytes_left) while (substream.bytes_left)
{ {
if ((size_t)*size + 1 > allocated_size) if (*size + 1 > allocated_size)
{ {
/* Allocate more storage. This tries to guess the /* Allocate more storage. This tries to guess the
* number of remaining entries. Round the division * number of remaining entries. Round the division
@@ -540,16 +604,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
status = false; status = false;
break; break;
} }
if (*size == PB_SIZE_MAX)
{
#ifndef PB_NO_ERRMSG
stream->errmsg = "too many array entries";
#endif
status = false;
break;
}
(*size)++; (*size)++;
} }
pb_close_string_substream(stream, &substream); pb_close_string_substream(stream, &substream);
@@ -559,12 +613,9 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
else else
{ {
/* Normal repeated field, i.e. only one item at a time. */ /* Normal repeated field, i.e. only one item at a time. */
pb_size_t *size = (pb_size_t*)iter->pSize; size_t *size = (size_t*)iter->pSize;
void *pItem; void *pItem;
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
(*size)++; (*size)++;
if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
return false; return false;
@@ -573,14 +624,14 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
initialize_pointer_field(pItem, iter); initialize_pointer_field(pItem, iter);
return func(stream, iter->pos, pItem); return func(stream, iter->pos, pItem);
} }
default: default:
PB_RETURN_ERROR(stream, "invalid field type"); PB_RETURN_ERROR(stream, "invalid field type");
} }
#endif #endif
} }
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_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{ {
pb_callback_t *pCallback = (pb_callback_t*)iter->pData; pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
@@ -627,18 +678,8 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type
} }
} }
static bool checkreturn decode_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_iterator_t *iter)
{ {
#ifdef PB_ENABLE_MALLOC
/* When decoding an oneof field, check if there is old data that must be
* released first. */
if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF)
{
if (!pb_release_union_field(stream, iter))
return false;
}
#endif
switch (PB_ATYPE(iter->pos->type)) switch (PB_ATYPE(iter->pos->type))
{ {
case PB_ATYPE_STATIC: case PB_ATYPE_STATIC:
@@ -655,45 +696,32 @@ static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_t
} }
} }
static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension)
{
/* Fake a field iterator for the extension field.
* It is not actually safe to advance this iterator, but decode_field
* will not even try to. */
const pb_field_t *field = (const pb_field_t*)extension->type->arg;
(void)pb_field_iter_begin(iter, field, extension->dest);
iter->pData = extension->dest;
iter->pSize = &extension->found;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
/* For pointer extensions, the pointer is stored directly
* in the extension structure. This avoids having an extra
* indirection. */
iter->pData = &extension->dest;
}
}
/* Default handler for extension fields. Expects a pb_field_t structure /* Default handler for extension fields. Expects a pb_field_t structure
* in extension->type->arg. */ * in extension->type->arg. */
static bool checkreturn default_extension_decoder(pb_istream_t *stream, static bool checkreturn default_extension_decoder(pb_istream_t *stream,
pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type)
{ {
const pb_field_t *field = (const pb_field_t*)extension->type->arg; const pb_field_t *field = (const pb_field_t*)extension->type->arg;
pb_field_iter_t iter; pb_field_iterator_t iter;
if (field->tag != tag) if (field->tag != tag)
return true; return true;
iter_from_extension(&iter, extension); iter.start = field;
extension->found = true; iter.pos = field;
iter.field_index = 0;
iter.required_field_index = 0;
iter.dest_struct = extension->dest;
iter.pData = extension->dest;
iter.pSize = &extension->found;
return decode_field(stream, wire_type, &iter); return decode_field(stream, wire_type, &iter);
} }
/* Try to decode an unknown field as an extension field. Tries each extension /* Try to decode an unknown field as an extension field. Tries each extension
* decoder in turn, until one of them handles the field or loop ends. */ * decoder in turn, until one of them handles the field or loop ends. */
static bool checkreturn decode_extension(pb_istream_t *stream, static bool checkreturn decode_extension(pb_istream_t *stream,
uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{ {
pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; pb_extension_t *extension = *(pb_extension_t* const *)iter->pData;
size_t pos = stream->bytes_left; size_t pos = stream->bytes_left;
@@ -718,103 +746,81 @@ static bool checkreturn decode_extension(pb_istream_t *stream,
/* Step through the iterator until an extension field is found or until all /* Step through the iterator until an extension field is found or until all
* entries have been checked. There can be only one extension field per * entries have been checked. There can be only one extension field per
* message. Returns false if no extension field is found. */ * message. Returns false if no extension field is found. */
static bool checkreturn find_extension_field(pb_field_iter_t *iter) static bool checkreturn find_extension_field(pb_field_iterator_t *iter)
{ {
const pb_field_t *start = iter->pos; unsigned start = iter->field_index;
do { do {
if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION)
return true; return true;
(void)pb_field_iter_next(iter); (void)pb_field_next(iter);
} while (iter->pos != start); } while (iter->field_index != start);
return false; return false;
} }
/* Initialize message fields to default values, recursively */ /* Initialize message fields to default values, recursively */
static void pb_field_set_to_default(pb_field_iter_t *iter) static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct)
{ {
pb_type_t type; pb_field_iterator_t iter;
type = iter->pos->type; pb_field_init(&iter, fields, dest_struct);
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) do
{ {
pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; pb_type_t type;
while (ext != NULL) type = iter.pos->type;
/* Avoid crash on empty message types (zero fields) */
if (iter.pos->tag == 0)
continue;
if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{ {
pb_field_iter_t ext_iter; if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL)
ext->found = false; {
iter_from_extension(&ext_iter, ext); /* Set has_field to false. Still initialize the optional field
pb_field_set_to_default(&ext_iter); * itself also. */
ext = ext->next; *(bool*)iter.pSize = false;
} }
} else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
else if (PB_ATYPE(type) == PB_ATYPE_STATIC) {
{ /* Set array count to 0, no need to initialize contents. */
bool init_data = true; *(size_t*)iter.pSize = 0;
if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) continue;
{ }
/* Set has_field to false. Still initialize the optional field
* itself also. */ if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE)
*(bool*)iter->pSize = false;
}
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
/* REPEATED: Set array count to 0, no need to initialize contents.
ONEOF: Set which_field to 0. */
*(pb_size_t*)iter->pSize = 0;
init_data = false;
}
if (init_data)
{
if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
{ {
/* Initialize submessage to defaults */ /* Initialize submessage to defaults */
pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); pb_message_set_to_defaults((const pb_field_t *) iter.pos->ptr, iter.pData);
} }
else if (iter->pos->ptr != NULL) else if (iter.pos->ptr != NULL)
{ {
/* Initialize to default value */ /* Initialize to default value */
memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); memcpy(iter.pData, iter.pos->ptr, iter.pos->data_size);
} }
else else
{ {
/* Initialize to zeros */ /* Initialize to zeros */
memset(iter->pData, 0, iter->pos->data_size); memset(iter.pData, 0, iter.pos->data_size);
} }
} }
} else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
/* Initialize the pointer to NULL. */
*(void**)iter->pData = NULL;
/* Initialize array count to 0. */
if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
PB_HTYPE(type) == PB_HTYPE_ONEOF)
{ {
*(pb_size_t*)iter->pSize = 0; /* Initialize the pointer to NULL. */
*(void**)iter.pData = NULL;
/* Initialize array count to 0. */
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
*(size_t*)iter.pSize = 0;
}
} }
} else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) {
{ /* Don't overwrite callback */
/* Don't overwrite callback */ }
} } while (pb_field_next(&iter));
}
static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin(&iter, fields, dest_struct))
return; /* Empty message type */
do
{
pb_field_set_to_default(&iter);
} while (pb_field_iter_next(&iter));
} }
/********************* /*********************
@@ -825,11 +831,9 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
{ {
uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint32_t extension_range_start = 0; uint32_t extension_range_start = 0;
pb_field_iter_t iter; pb_field_iterator_t iter;
/* Return value ignored, as empty message types will be correctly handled by pb_field_init(&iter, fields, dest_struct);
* pb_field_iter_find() anyway. */
(void)pb_field_iter_begin(&iter, fields, dest_struct);
while (stream->bytes_left) while (stream->bytes_left)
{ {
@@ -845,7 +849,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
return false; return false;
} }
if (!pb_field_iter_find(&iter, tag)) if (!pb_field_find(&iter, tag))
{ {
/* No match found, check if it matches an extension. */ /* No match found, check if it matches an extension. */
if (tag >= extension_range_start) if (tag >= extension_range_start)
@@ -898,7 +902,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
do { do {
req_field_count = iter.required_field_index; req_field_count = iter.required_field_index;
last_type = iter.pos->type; last_type = iter.pos->type;
} while (pb_field_iter_next(&iter)); } while (pb_field_next(&iter));
/* Fixup if last field was also required. */ /* Fixup if last field was also required. */
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
@@ -947,86 +951,11 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *
} }
#ifdef PB_ENABLE_MALLOC #ifdef PB_ENABLE_MALLOC
/* Given an oneof field, if there has already been a field inside this oneof, static void pb_release_single_field(const pb_field_iterator_t *iter)
* release it before overwriting with a different one. */
static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter)
{
pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */
pb_size_t new_tag = iter->pos->tag; /* New which_ value */
if (old_tag == 0)
return true; /* Ok, no old data in union */
if (old_tag == new_tag)
return true; /* Ok, old data is of same type => merge */
/* Release old data. The find can fail if the message struct contains
* invalid data. */
if (!pb_field_iter_find(iter, old_tag))
PB_RETURN_ERROR(stream, "invalid union tag");
pb_release_single_field(iter);
/* Restore iterator to where it should be.
* This shouldn't fail unless the pb_field_t structure is corrupted. */
if (!pb_field_iter_find(iter, new_tag))
PB_RETURN_ERROR(stream, "iterator error");
return true;
}
static void pb_release_single_field(const pb_field_iter_t *iter)
{ {
pb_type_t type; pb_type_t type;
type = iter->pos->type; type = iter->pos->type;
if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
if (*(pb_size_t*)iter->pSize != iter->pos->tag)
return; /* This is not the current field in the union */
}
/* Release anything contained inside an extension or submsg.
* This has to be done even if the submsg itself is statically
* allocated. */
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
/* Release fields from all extensions in the linked list */
pb_extension_t *ext = *(pb_extension_t**)iter->pData;
while (ext != NULL)
{
pb_field_iter_t ext_iter;
iter_from_extension(&ext_iter, ext);
pb_release_single_field(&ext_iter);
ext = ext->next;
}
}
else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
{
/* Release fields in submessage or submsg array */
void *pItem = iter->pData;
pb_size_t count = 1;
if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
pItem = *(void**)iter->pData;
}
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(pb_size_t*)iter->pSize;
}
if (pItem)
{
while (count--)
{
pb_release((const pb_field_t*)iter->pos->ptr, pItem);
pItem = (uint8_t*)pItem + iter->pos->data_size;
}
}
}
if (PB_ATYPE(type) == PB_ATYPE_POINTER) if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{ {
if (PB_HTYPE(type) == PB_HTYPE_REPEATED && if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
@@ -1041,13 +970,29 @@ static void pb_release_single_field(const pb_field_iter_t *iter)
pb_free(*pItem); pb_free(*pItem);
*pItem++ = NULL; *pItem++ = NULL;
} }
}
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
/* We are going to release the array, so set the size to 0 */
*(pb_size_t*)iter->pSize = 0; *(pb_size_t*)iter->pSize = 0;
} }
else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
{
/* Release fields in submessages */
void *pItem = *(void**)iter->pData;
if (pItem)
{
pb_size_t count = 1;
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(pb_size_t*)iter->pSize;
*(pb_size_t*)iter->pSize = 0;
}
while (count--)
{
pb_release((const pb_field_t*)iter->pos->ptr, pItem);
pItem = (uint8_t*)pItem + iter->pos->data_size;
}
}
}
/* Release main item */ /* Release main item */
pb_free(*(void**)iter->pData); pb_free(*(void**)iter->pData);
@@ -1057,15 +1002,16 @@ static void pb_release_single_field(const pb_field_iter_t *iter)
void pb_release(const pb_field_t fields[], void *dest_struct) void pb_release(const pb_field_t fields[], void *dest_struct)
{ {
pb_field_iter_t iter; pb_field_iterator_t iter;
pb_field_init(&iter, fields, dest_struct);
if (!pb_field_iter_begin(&iter, fields, dest_struct))
if (iter.pos->tag == 0)
return; /* Empty message type */ return; /* Empty message type */
do do
{ {
pb_release_single_field(&iter); pb_release_single_field(&iter);
} while (pb_field_iter_next(&iter)); } while (pb_field_next(&iter));
} }
#endif #endif
@@ -1130,88 +1076,62 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint64_t value; uint64_t value;
int64_t svalue;
int64_t clamped;
if (!pb_decode_varint(stream, &value)) if (!pb_decode_varint(stream, &value))
return false; return false;
/* See issue 97: Google's C++ protobuf allows negative varint values to
* be cast as int32_t, instead of the int64_t that should be used when
* encoding. Previous nanopb versions had a bug in encoding. In order to
* 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)
svalue = (int64_t)value;
else
svalue = (int32_t)value;
switch (field->data_size) switch (field->data_size)
{ {
case 1: clamped = *(int8_t*)dest = (int8_t)svalue; break; case 1: *(int8_t*)dest = (int8_t)value; break;
case 2: clamped = *(int16_t*)dest = (int16_t)svalue; break; case 2: *(int16_t*)dest = (int16_t)value; break;
case 4: clamped = *(int32_t*)dest = (int32_t)svalue; break; case 4: *(int32_t*)dest = (int32_t)value; break;
case 8: clamped = *(int64_t*)dest = svalue; break; case 8: *(int64_t*)dest = (int64_t)value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size"); default: PB_RETURN_ERROR(stream, "invalid data_size");
} }
if (clamped != svalue)
PB_RETURN_ERROR(stream, "integer too large");
return true; return true;
} }
static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint64_t value, clamped; uint64_t value;
if (!pb_decode_varint(stream, &value)) if (!pb_decode_varint(stream, &value))
return false; return false;
switch (field->data_size) switch (field->data_size)
{ {
case 1: clamped = *(uint8_t*)dest = (uint8_t)value; break; case 4: *(uint32_t*)dest = (uint32_t)value; break;
case 2: clamped = *(uint16_t*)dest = (uint16_t)value; break; case 8: *(uint64_t*)dest = 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"); default: PB_RETURN_ERROR(stream, "invalid data_size");
} }
if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
return true; return true;
} }
static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
int64_t value, clamped; int64_t value;
if (!pb_decode_svarint(stream, &value)) if (!pb_decode_svarint(stream, &value))
return false; return false;
switch (field->data_size) switch (field->data_size)
{ {
case 1: clamped = *(int8_t*)dest = (int8_t)value; break; case 4: *(int32_t*)dest = (int32_t)value; break;
case 2: clamped = *(int16_t*)dest = (int16_t)value; break; case 8: *(int64_t*)dest = 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"); default: PB_RETURN_ERROR(stream, "invalid data_size");
} }
if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
return true; return true;
} }
static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
PB_UNUSED(field); UNUSED(field);
return pb_decode_fixed32(stream, dest); return pb_decode_fixed32(stream, dest);
} }
static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
PB_UNUSED(field); UNUSED(field);
return pb_decode_fixed64(stream, dest); return pb_decode_fixed64(stream, dest);
} }
@@ -1224,9 +1144,6 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
if (!pb_decode_varint32(stream, &size)) if (!pb_decode_varint32(stream, &size))
return false; return false;
if (size > PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "bytes overflow");
alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size);
if (size > alloc_size) if (size > alloc_size)
PB_RETURN_ERROR(stream, "size too large"); PB_RETURN_ERROR(stream, "size too large");
@@ -1247,8 +1164,9 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
PB_RETURN_ERROR(stream, "bytes overflow"); PB_RETURN_ERROR(stream, "bytes overflow");
bdest = (pb_bytes_array_t*)dest; bdest = (pb_bytes_array_t*)dest;
} }
bdest->size = size;
bdest->size = (pb_size_t)size;
return pb_read(stream, bdest->bytes, size); return pb_read(stream, bdest->bytes, size);
} }

View File

@@ -3,8 +3,8 @@
* field descriptions created by nanopb_generator.py. * field descriptions created by nanopb_generator.py.
*/ */
#ifndef PB_DECODE_H_INCLUDED #ifndef _PB_DECODE_H_
#define PB_DECODE_H_INCLUDED #define _PB_DECODE_H_
#include "pb.h" #include "pb.h"
@@ -25,7 +25,7 @@ extern "C" {
* is different than from the main stream. Don't use bytes_left to compute * is different than from the main stream. Don't use bytes_left to compute
* any pointers. * any pointers.
*/ */
struct pb_istream_s struct _pb_istream_t
{ {
#ifdef PB_BUFFER_ONLY #ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration. /* Callback pointer is not used in buffer-only configuration.

View File

@@ -5,7 +5,6 @@
#include "pb.h" #include "pb.h"
#include "pb_encode.h" #include "pb_encode.h"
#include "pb_common.h"
/* Use the GCC warn_unused_result attribute to check that all return values /* Use the GCC warn_unused_result attribute to check that all return values
* are propagated correctly. On other compilers and gcc before 3.4.0 just * are propagated correctly. On other compilers and gcc before 3.4.0 just
@@ -246,21 +245,10 @@ static bool checkreturn encode_basic_field(pb_ostream_t *stream,
break; break;
case PB_HTYPE_REPEATED: case PB_HTYPE_REPEATED:
if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func)) if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
return false; return false;
break; break;
case PB_HTYPE_ONEOF:
if (*(const pb_size_t*)pSize == field->tag)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!func(stream, field, pData))
return false;
}
break;
default: default:
PB_RETURN_ERROR(stream, "invalid field type"); PB_RETURN_ERROR(stream, "invalid field type");
} }
@@ -313,18 +301,7 @@ static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
const pb_extension_t *extension) const pb_extension_t *extension)
{ {
const pb_field_t *field = (const pb_field_t*)extension->type->arg; const pb_field_t *field = (const pb_field_t*)extension->type->arg;
return encode_field(stream, field, extension->dest);
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
/* For pointer extensions, the pointer is stored directly
* in the extension structure. This avoids having an extra
* indirection. */
return encode_field(stream, field, &extension->dest);
}
else
{
return encode_field(stream, field, extension->dest);
}
} }
/* Walk through all the registered extensions and give them a chance /* Walk through all the registered extensions and give them a chance
@@ -333,7 +310,7 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData) const pb_field_t *field, const void *pData)
{ {
const pb_extension_t *extension = *(const pb_extension_t* const *)pData; const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
PB_UNUSED(field); UNUSED(field);
while (extension) while (extension)
{ {
@@ -356,38 +333,42 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream,
* Encode all fields * * Encode all fields *
*********************/ *********************/
static void *remove_const(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator
* logic for both encoding and decoding. */
union {
void *p1;
const void *p2;
} t;
t.p2 = p;
return t.p1;
}
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
{ {
pb_field_iter_t iter; const pb_field_t *field = fields;
if (!pb_field_iter_begin(&iter, fields, remove_const(src_struct))) const void *pData = src_struct;
return true; /* Empty message type */ size_t prev_size = 0;
do { while (field->tag != 0)
if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) {
pData = (const char*)pData + prev_size + field->data_offset;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
prev_size = sizeof(const void*);
else
prev_size = field->data_size;
/* Special case for static arrays */
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
{
prev_size *= field->array_size;
}
if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION)
{ {
/* Special case for the extension field placeholder */ /* Special case for the extension field placeholder */
if (!encode_extension_field(stream, iter.pos, iter.pData)) if (!encode_extension_field(stream, field, pData))
return false; return false;
} }
else else
{ {
/* Regular field */ /* Regular field */
if (!encode_field(stream, iter.pos, iter.pData)) if (!encode_field(stream, field, pData))
return false; return false;
} }
} while (pb_field_iter_next(&iter));
field++;
}
return true; return true;
} }
@@ -578,7 +559,7 @@ static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *fi
int64_t value = 0; int64_t value = 0;
/* Cases 1 and 2 are for compilers that have smaller types for bool /* Cases 1 and 2 are for compilers that have smaller types for bool
* or enums, and for int_size option. */ * or enums. */
switch (field->data_size) switch (field->data_size)
{ {
case 1: value = *(const int8_t*)src; break; case 1: value = *(const int8_t*)src; break;
@@ -597,8 +578,6 @@ static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *f
switch (field->data_size) 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 4: value = *(const uint32_t*)src; break;
case 8: value = *(const uint64_t*)src; break; case 8: value = *(const uint64_t*)src; break;
default: PB_RETURN_ERROR(stream, "invalid data_size"); default: PB_RETURN_ERROR(stream, "invalid data_size");
@@ -613,8 +592,6 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f
switch (field->data_size) 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 4: value = *(const int32_t*)src; break;
case 8: value = *(const int64_t*)src; break; case 8: value = *(const int64_t*)src; break;
default: PB_RETURN_ERROR(stream, "invalid data_size"); default: PB_RETURN_ERROR(stream, "invalid data_size");
@@ -625,13 +602,13 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f
static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
PB_UNUSED(field); UNUSED(field);
return pb_encode_fixed64(stream, src); return pb_encode_fixed64(stream, src);
} }
static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
PB_UNUSED(field); UNUSED(field);
return pb_encode_fixed32(stream, src); return pb_encode_fixed32(stream, src);
} }
@@ -656,6 +633,7 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
/* strnlen() is not always available, so just use a loop */
size_t size = 0; size_t size = 0;
size_t max_size = field->data_size; size_t max_size = field->data_size;
const char *p = (const char*)src; const char *p = (const char*)src;
@@ -669,7 +647,6 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi
} }
else else
{ {
/* strnlen() is not always available, so just use a loop */
while (size < max_size && *p != '\0') while (size < max_size && *p != '\0')
{ {
size++; size++;

View File

@@ -3,8 +3,8 @@
* field descriptions created by nanopb_generator.py. * field descriptions created by nanopb_generator.py.
*/ */
#ifndef PB_ENCODE_H_INCLUDED #ifndef _PB_ENCODE_H_
#define PB_ENCODE_H_INCLUDED #define _PB_ENCODE_H_
#include "pb.h" #include "pb.h"
@@ -24,7 +24,7 @@ extern "C" {
* 4) Substreams will modify max_size and bytes_written. Don't use them * 4) Substreams will modify max_size and bytes_written. Don't use them
* to calculate any pointers. * to calculate any pointers.
*/ */
struct pb_ostream_s struct _pb_ostream_t
{ {
#ifdef PB_BUFFER_ONLY #ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration. /* Callback pointer is not used in buffer-only configuration.

View File

@@ -10,12 +10,12 @@ coverage:
# LCOV does not like the newer gcov format # LCOV does not like the newer gcov format
scons CC=gcc-4.6 CXX=gcc-4.6 scons CC=gcc-4.6 CXX=gcc-4.6
# We are only interested in pb_encode.o and pb_decode.o
find build -name '*.gcda' -and \! \( -name '*pb_encode*' -or -name '*pb_decode*' \) -exec rm '{}' \;
# Collect the data # Collect the data
mkdir build/coverage mkdir build/coverage
lcov --base-directory . --directory build/ --gcov-tool gcov-4.6 -c -o build/coverage/nanopb.info lcov --base-directory . --directory build/ --gcov-tool gcov-4.6 -c -o build/coverage/nanopb.info
# Remove the test code from results
lcov -r build/coverage/nanopb.info '*tests*' -o build/coverage/nanopb.info
# Generate HTML # Generate HTML
genhtml -o build/coverage build/coverage/nanopb.info genhtml -o build/coverage build/coverage/nanopb.info

View File

@@ -72,11 +72,6 @@ if not env.GetOption('clean'):
else: else:
conf.env.Append(PROTOCPATH = '/usr/include') conf.env.Append(PROTOCPATH = '/usr/include')
# Check protoc version
status, output = conf.TryAction('$PROTOC --version > $TARGET')
if status:
conf.env['PROTOC_VERSION'] = output
# Check if libmudflap is available (only with GCC) # Check if libmudflap is available (only with GCC)
if 'gcc' in env['CC']: if 'gcc' in env['CC']:
if conf.CheckLib('mudflap'): if conf.CheckLib('mudflap'):
@@ -126,6 +121,9 @@ elif 'cl' in env['CC']:
# More strict checks on the nanopb core # More strict checks on the nanopb core
env.Append(CORECFLAGS = '/W4') env.Append(CORECFLAGS = '/W4')
# PB_RETURN_ERROR triggers C4127 because of while(0)
env.Append(CFLAGS = '/wd4127')
elif 'tcc' in env['CC']: elif 'tcc' in env['CC']:
# Tiny C Compiler # Tiny C Compiler
env.Append(CFLAGS = '-Wall -Werror -g') env.Append(CFLAGS = '-Wall -Werror -g')
@@ -138,18 +136,12 @@ elif 'g++' in env['CXX'] or 'gcc' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'cl' in env['CXX']: elif 'cl' in env['CXX']:
env.Append(CXXFLAGS = '/Zi /W2 /WX') env.Append(CXXFLAGS = '/Zi /W2 /WX')
# Now include the SConscript files from all subdirectories # Now include the SConscript files from all subdirectories
import os.path import os.path
env['VARIANT_DIR'] = 'build' env['VARIANT_DIR'] = 'build'
env['BUILD'] = '#' + env['VARIANT_DIR'] env['BUILD'] = '#' + env['VARIANT_DIR']
env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common' env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common'
# Include common/SConscript first to make sure its exports are available
# to other SConscripts.
SConscript("common/SConscript", exports = 'env', variant_dir = env['VARIANT_DIR'] + '/common')
for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'): for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'):
if str(subdir).startswith("common"): continue
SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir))) SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir)))

View File

@@ -4,8 +4,8 @@
Import("env") Import("env")
env.NanopbProto(["alltypes", "alltypes.options"]) env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o"])
dec = env.Program(["decode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = env.Program(["decode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_decode.o"])
# Test the round-trip from nanopb encoder to nanopb decoder # Test the round-trip from nanopb encoder to nanopb decoder
env.RunTest(enc) env.RunTest(enc)

View File

@@ -101,12 +101,6 @@ message AllTypes {
optional MyEnum opt_enum = 57 [default = Second]; optional MyEnum opt_enum = 57 [default = Second];
optional EmptyMessage opt_emptymsg = 58; optional EmptyMessage opt_emptymsg = 58;
oneof oneof
{
SubMessage oneof_msg1 = 59;
EmptyMessage oneof_msg2 = 60;
}
// Check that extreme integer values are handled correctly // Check that extreme integer values are handled correctly
required Limits req_limits = 98; required Limits req_limits = 98;

View File

@@ -125,8 +125,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
TEST(alltypes.has_opt_enum == false); TEST(alltypes.has_opt_enum == false);
TEST(alltypes.opt_enum == MyEnum_Second); TEST(alltypes.opt_enum == MyEnum_Second);
TEST(alltypes.has_opt_emptymsg == false); TEST(alltypes.has_opt_emptymsg == false);
TEST(alltypes.which_oneof == 0);
} }
else else
{ {
@@ -172,10 +170,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
TEST(alltypes.has_opt_enum == true); TEST(alltypes.has_opt_enum == true);
TEST(alltypes.opt_enum == MyEnum_Truth); TEST(alltypes.opt_enum == MyEnum_Truth);
TEST(alltypes.has_opt_emptymsg == true); TEST(alltypes.has_opt_emptymsg == true);
TEST(alltypes.which_oneof == AllTypes_oneof_msg1_tag);
TEST(strcmp(alltypes.oneof.oneof_msg1.substuff1, "4059") == 0);
TEST(alltypes.oneof.oneof_msg1.substuff2 == 4059);
} }
TEST(alltypes.req_limits.int32_min == INT32_MIN); TEST(alltypes.req_limits.int32_min == INT32_MIN);

View File

@@ -121,10 +121,6 @@ int main(int argc, char **argv)
alltypes.has_opt_enum = true; alltypes.has_opt_enum = true;
alltypes.opt_enum = MyEnum_Truth; alltypes.opt_enum = MyEnum_Truth;
alltypes.has_opt_emptymsg = true; alltypes.has_opt_emptymsg = true;
alltypes.which_oneof = AllTypes_oneof_msg1_tag;
strcpy(alltypes.oneof.oneof_msg1.substuff1, "4059");
alltypes.oneof.oneof_msg1.substuff2 = 4059;
} }
alltypes.end = 1099; alltypes.end = 1099;

View File

@@ -6,8 +6,8 @@ c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c) env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"]) env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_encode.o"])
dec = env.Program(["decode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = env.Program(["decode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_decode.o"])
refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX" refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX"

View File

@@ -1,4 +1,3 @@
# Generate all fields as callbacks. # Generate all fields as callbacks.
AllTypes.* type:FT_CALLBACK AllTypes.* type:FT_CALLBACK
SubMessage.substuff1 max_size:16 SubMessage.substuff1 max_size:16
AllTypes.oneof no_unions:true

View File

@@ -214,8 +214,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
int64_t opt_sfixed64 = 3052; int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0f; double opt_double = 3053.0f;
SubMessage opt_submsg = {"3056", 3056}; SubMessage opt_submsg = {"3056", 3056};
SubMessage oneof_msg1 = {"4059", 4059};
/* Bind callbacks for required fields */ /* Bind callbacks for required fields */
AllTypes alltypes; AllTypes alltypes;
@@ -394,9 +392,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
alltypes.opt_enum.arg = (void*)MyEnum_Truth; alltypes.opt_enum.arg = (void*)MyEnum_Truth;
alltypes.opt_emptymsg.funcs.decode = &read_emptymsg; alltypes.opt_emptymsg.funcs.decode = &read_emptymsg;
alltypes.oneof_msg1.funcs.decode = &read_submsg;
alltypes.oneof_msg1.arg = &oneof_msg1;
} }
return pb_decode(stream, AllTypes_fields, &alltypes); return pb_decode(stream, AllTypes_fields, &alltypes);

View File

@@ -202,8 +202,6 @@ int main(int argc, char **argv)
double opt_double = 3053.0f; double opt_double = 3053.0f;
SubMessage opt_submsg = {"3056", 3056}; SubMessage opt_submsg = {"3056", 3056};
SubMessage oneof_msg1 = {"4059", 4059};
/* Bind callbacks for required fields */ /* Bind callbacks for required fields */
AllTypes alltypes = {{{0}}}; AllTypes alltypes = {{{0}}};
@@ -374,9 +372,6 @@ int main(int argc, char **argv)
alltypes.opt_enum.arg = (void*)MyEnum_Truth; alltypes.opt_enum.arg = (void*)MyEnum_Truth;
alltypes.opt_emptymsg.funcs.encode = &write_emptymsg; alltypes.opt_emptymsg.funcs.encode = &write_emptymsg;
alltypes.oneof_msg1.funcs.encode = &write_submsg;
alltypes.oneof_msg1.arg = &oneof_msg1;
} }
alltypes.end.funcs.encode = &write_varint; alltypes.end.funcs.encode = &write_varint;

View File

@@ -1,22 +1,30 @@
# Encode the AllTypes message using pointers for all fields, and verify the # Encode the AllTypes message using pointers for all fields, and verify the
# output against the normal AllTypes test case. # output against the normal AllTypes test case.
Import("env", "malloc_env") Import("env")
# We need our own pb_decode.o for the malloc support
env = env.Clone()
env.Append(CPPDEFINES = {'PB_ENABLE_MALLOC': 1});
# Disable libmudflap, because it will confuse valgrind
# and other memory leak detection tools.
if '-fmudflap' in env["CCFLAGS"]:
env["CCFLAGS"].remove("-fmudflap")
env["LINKFLAGS"].remove("-fmudflap")
env["LIBS"].remove("mudflap")
strict = env.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_with_malloc.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_with_malloc.o", "$NANOPB/pb_encode.c")
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c) env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"]) env.NanopbProto(["alltypes", "alltypes.options"])
enc = malloc_env.Program(["encode_alltypes_pointer.c", enc = env.Program(["encode_alltypes_pointer.c", "alltypes.pb.c", "pb_encode_with_malloc.o"])
"alltypes.pb.c", dec = env.Program(["decode_alltypes_pointer.c", "alltypes.pb.c", "pb_decode_with_malloc.o"])
"$COMMON/pb_encode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
"$COMMON/malloc_wrappers.o"])
dec = malloc_env.Program(["decode_alltypes_pointer.c",
"alltypes.pb.c",
"$COMMON/pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
"$COMMON/malloc_wrappers.o"])
# Encode and compare results to non-pointer alltypes test case # Encode and compare results to non-pointer alltypes test case
env.RunTest(enc) env.RunTest(enc)
@@ -27,7 +35,7 @@ valgrind = env.WhereIs('valgrind')
kwargs = {} kwargs = {}
if valgrind: if valgrind:
kwargs['COMMAND'] = valgrind kwargs['COMMAND'] = valgrind
kwargs['ARGS'] = ["-q", "--error-exitcode=99", dec[0].abspath] kwargs['ARGS'] = ["-q", dec[0].abspath]
env.RunTest("decode_alltypes.output", [dec, "encode_alltypes_pointer.output"], **kwargs) env.RunTest("decode_alltypes.output", [dec, "encode_alltypes_pointer.output"], **kwargs)

View File

@@ -99,8 +99,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
TEST(alltypes.opt_bytes == NULL); TEST(alltypes.opt_bytes == NULL);
TEST(alltypes.opt_submsg == NULL); TEST(alltypes.opt_submsg == NULL);
TEST(alltypes.opt_enum == NULL); TEST(alltypes.opt_enum == NULL);
TEST(alltypes.which_oneof == 0);
} }
else else
{ {
@@ -127,10 +125,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
TEST(alltypes.opt_submsg && *alltypes.opt_submsg->substuff2 == 3056); TEST(alltypes.opt_submsg && *alltypes.opt_submsg->substuff2 == 3056);
TEST(alltypes.opt_enum && *alltypes.opt_enum == MyEnum_Truth); TEST(alltypes.opt_enum && *alltypes.opt_enum == MyEnum_Truth);
TEST(alltypes.opt_emptymsg); TEST(alltypes.opt_emptymsg);
TEST(alltypes.which_oneof == AllTypes_oneof_msg1_tag);
TEST(alltypes.oneof.oneof_msg1 && strcmp(alltypes.oneof.oneof_msg1->substuff1, "4059") == 0);
TEST(alltypes.oneof.oneof_msg1->substuff2 && *alltypes.oneof.oneof_msg1->substuff2 == 4059);
} }
TEST(alltypes.req_limits->int32_min && *alltypes.req_limits->int32_min == INT32_MIN); TEST(alltypes.req_limits->int32_min && *alltypes.req_limits->int32_min == INT32_MIN);

View File

@@ -84,9 +84,6 @@ int main(int argc, char **argv)
MyEnum opt_enum = MyEnum_Truth; MyEnum opt_enum = MyEnum_Truth;
EmptyMessage opt_emptymsg = {0}; EmptyMessage opt_emptymsg = {0};
static int32_t oneof_substuff = 4059;
SubMessage oneof_msg1 = {"4059", &oneof_substuff};
/* Values for the Limits message. */ /* Values for the Limits message. */
static int32_t int32_min = INT32_MIN; static int32_t int32_min = INT32_MIN;
static int32_t int32_max = INT32_MAX; static int32_t int32_max = INT32_MAX;
@@ -167,9 +164,6 @@ int main(int argc, char **argv)
alltypes.opt_submsg = &opt_submsg; alltypes.opt_submsg = &opt_submsg;
alltypes.opt_enum = &opt_enum; alltypes.opt_enum = &opt_enum;
alltypes.opt_emptymsg = &opt_emptymsg; alltypes.opt_emptymsg = &opt_emptymsg;
alltypes.which_oneof = AllTypes_oneof_msg1_tag;
alltypes.oneof.oneof_msg1 = &oneof_msg1;
} }
alltypes.end = &end; alltypes.end = &end;

View File

@@ -3,8 +3,8 @@
Import("env") Import("env")
enc = env.Program(["encode_legacy.c", "alltypes_legacy.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_legacy.c", "alltypes_legacy.c", "$COMMON/pb_encode.o"])
dec = env.Program(["decode_legacy.c", "alltypes_legacy.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = env.Program(["decode_legacy.c", "alltypes_legacy.c", "$COMMON/pb_decode.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_legacy.output"]) env.RunTest([dec, "encode_legacy.output"])

View File

@@ -1,37 +1,27 @@
/* Automatically generated nanopb constant definitions */ /* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.0-dev at Tue Aug 19 17:53:24 2014. */ /* Generated by 0.2.0-dev at Sun Feb 17 00:09:53 2013. */
/* This is a file generated using nanopb-0.2.0-dev.
* It is used as a part of test suite in order to detect any
* incompatible changes made to the generator in future versions.
*/
#include "alltypes_legacy.h" #include "alltypes_legacy.h"
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
const char SubMessage_substuff1_default[16] = "1"; const char SubMessage_substuff1_default[16] = "1";
const int32_t SubMessage_substuff2_default = 2; const int32_t SubMessage_substuff2_default = 2;
const uint32_t SubMessage_substuff3_default = 3u; const uint32_t SubMessage_substuff3_default = 3;
const int32_t Limits_int32_min_default = 2147483647;
const int32_t Limits_int32_max_default = -2147483647;
const uint32_t Limits_uint32_min_default = 4294967295u;
const uint32_t Limits_uint32_max_default = 0u;
const int64_t Limits_int64_min_default = 9223372036854775807ll;
const int64_t Limits_int64_max_default = -9223372036854775807ll;
const uint64_t Limits_uint64_min_default = 18446744073709551615ull;
const uint64_t Limits_uint64_max_default = 0ull;
const HugeEnum Limits_enum_min_default = HugeEnum_Positive;
const HugeEnum Limits_enum_max_default = HugeEnum_Negative;
const int32_t AllTypes_opt_int32_default = 4041; const int32_t AllTypes_opt_int32_default = 4041;
const int64_t AllTypes_opt_int64_default = 4042ll; const int64_t AllTypes_opt_int64_default = 4042;
const uint32_t AllTypes_opt_uint32_default = 4043u; const uint32_t AllTypes_opt_uint32_default = 4043;
const uint64_t AllTypes_opt_uint64_default = 4044ull; const uint64_t AllTypes_opt_uint64_default = 4044;
const int32_t AllTypes_opt_sint32_default = 4045; const int32_t AllTypes_opt_sint32_default = 4045;
const int64_t AllTypes_opt_sint64_default = 4046; const int64_t AllTypes_opt_sint64_default = 4046;
const bool AllTypes_opt_bool_default = false; const bool AllTypes_opt_bool_default = false;
const uint32_t AllTypes_opt_fixed32_default = 4048u; const uint32_t AllTypes_opt_fixed32_default = 4048;
const int32_t AllTypes_opt_sfixed32_default = 4049; const int32_t AllTypes_opt_sfixed32_default = 4049;
const float AllTypes_opt_float_default = 4050; const float AllTypes_opt_float_default = 4050;
const uint64_t AllTypes_opt_fixed64_default = 4051ull; const uint64_t AllTypes_opt_fixed64_default = 4051;
const int64_t AllTypes_opt_sfixed64_default = 4052ll; const int64_t AllTypes_opt_sfixed64_default = 4052;
const double AllTypes_opt_double_default = 4053; const double AllTypes_opt_double_default = 4053;
const char AllTypes_opt_string_default[16] = "4054"; const char AllTypes_opt_string_default[16] = "4054";
const AllTypes_opt_bytes_t AllTypes_opt_bytes_default = {4, {0x34,0x30,0x35,0x35}}; const AllTypes_opt_bytes_t AllTypes_opt_bytes_default = {4, {0x34,0x30,0x35,0x35}};
@@ -39,115 +29,65 @@ const MyEnum AllTypes_opt_enum_default = MyEnum_Second;
const pb_field_t SubMessage_fields[4] = { const pb_field_t SubMessage_fields[4] = {
PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, SubMessage, substuff1, substuff1, &SubMessage_substuff1_default), PB_FIELD( 1, STRING , REQUIRED, STATIC, SubMessage, substuff1, substuff1, &SubMessage_substuff1_default),
PB_FIELD( 2, INT32 , REQUIRED, STATIC , OTHER, SubMessage, substuff2, substuff1, &SubMessage_substuff2_default), PB_FIELD( 2, INT32 , REQUIRED, STATIC, SubMessage, substuff2, substuff1, &SubMessage_substuff2_default),
PB_FIELD( 3, FIXED32 , OPTIONAL, STATIC , OTHER, SubMessage, substuff3, substuff2, &SubMessage_substuff3_default), PB_FIELD( 3, FIXED32 , OPTIONAL, STATIC, SubMessage, substuff3, substuff2, &SubMessage_substuff3_default),
PB_LAST_FIELD PB_LAST_FIELD
}; };
const pb_field_t EmptyMessage_fields[1] = { const pb_field_t AllTypes_fields[53] = {
PB_FIELD( 1, INT32 , REQUIRED, STATIC, AllTypes, req_int32, req_int32, 0),
PB_FIELD( 2, INT64 , REQUIRED, STATIC, AllTypes, req_int64, req_int32, 0),
PB_FIELD( 3, UINT32 , REQUIRED, STATIC, AllTypes, req_uint32, req_int64, 0),
PB_FIELD( 4, UINT64 , REQUIRED, STATIC, AllTypes, req_uint64, req_uint32, 0),
PB_FIELD( 5, SINT32 , REQUIRED, STATIC, AllTypes, req_sint32, req_uint64, 0),
PB_FIELD( 6, SINT64 , REQUIRED, STATIC, AllTypes, req_sint64, req_sint32, 0),
PB_FIELD( 7, BOOL , REQUIRED, STATIC, AllTypes, req_bool, req_sint64, 0),
PB_FIELD( 8, FIXED32 , REQUIRED, STATIC, AllTypes, req_fixed32, req_bool, 0),
PB_FIELD( 9, SFIXED32, REQUIRED, STATIC, AllTypes, req_sfixed32, req_fixed32, 0),
PB_FIELD( 10, FLOAT , REQUIRED, STATIC, AllTypes, req_float, req_sfixed32, 0),
PB_FIELD( 11, FIXED64 , REQUIRED, STATIC, AllTypes, req_fixed64, req_float, 0),
PB_FIELD( 12, SFIXED64, REQUIRED, STATIC, AllTypes, req_sfixed64, req_fixed64, 0),
PB_FIELD( 13, DOUBLE , REQUIRED, STATIC, AllTypes, req_double, req_sfixed64, 0),
PB_FIELD( 14, STRING , REQUIRED, STATIC, AllTypes, req_string, req_double, 0),
PB_FIELD( 15, BYTES , REQUIRED, STATIC, AllTypes, req_bytes, req_string, 0),
PB_FIELD( 16, MESSAGE , REQUIRED, STATIC, AllTypes, req_submsg, req_bytes, &SubMessage_fields),
PB_FIELD( 17, ENUM , REQUIRED, STATIC, AllTypes, req_enum, req_submsg, 0),
PB_FIELD( 21, INT32 , REPEATED, STATIC, AllTypes, rep_int32, req_enum, 0),
PB_FIELD( 22, INT64 , REPEATED, STATIC, AllTypes, rep_int64, rep_int32, 0),
PB_FIELD( 23, UINT32 , REPEATED, STATIC, AllTypes, rep_uint32, rep_int64, 0),
PB_FIELD( 24, UINT64 , REPEATED, STATIC, AllTypes, rep_uint64, rep_uint32, 0),
PB_FIELD( 25, SINT32 , REPEATED, STATIC, AllTypes, rep_sint32, rep_uint64, 0),
PB_FIELD( 26, SINT64 , REPEATED, STATIC, AllTypes, rep_sint64, rep_sint32, 0),
PB_FIELD( 27, BOOL , REPEATED, STATIC, AllTypes, rep_bool, rep_sint64, 0),
PB_FIELD( 28, FIXED32 , REPEATED, STATIC, AllTypes, rep_fixed32, rep_bool, 0),
PB_FIELD( 29, SFIXED32, REPEATED, STATIC, AllTypes, rep_sfixed32, rep_fixed32, 0),
PB_FIELD( 30, FLOAT , REPEATED, STATIC, AllTypes, rep_float, rep_sfixed32, 0),
PB_FIELD( 31, FIXED64 , REPEATED, STATIC, AllTypes, rep_fixed64, rep_float, 0),
PB_FIELD( 32, SFIXED64, REPEATED, STATIC, AllTypes, rep_sfixed64, rep_fixed64, 0),
PB_FIELD( 33, DOUBLE , REPEATED, STATIC, AllTypes, rep_double, rep_sfixed64, 0),
PB_FIELD( 34, STRING , REPEATED, STATIC, AllTypes, rep_string, rep_double, 0),
PB_FIELD( 35, BYTES , REPEATED, STATIC, AllTypes, rep_bytes, rep_string, 0),
PB_FIELD( 36, MESSAGE , REPEATED, STATIC, AllTypes, rep_submsg, rep_bytes, &SubMessage_fields),
PB_FIELD( 37, ENUM , REPEATED, STATIC, AllTypes, rep_enum, rep_submsg, 0),
PB_FIELD( 41, INT32 , OPTIONAL, STATIC, AllTypes, opt_int32, rep_enum, &AllTypes_opt_int32_default),
PB_FIELD( 42, INT64 , OPTIONAL, STATIC, AllTypes, opt_int64, opt_int32, &AllTypes_opt_int64_default),
PB_FIELD( 43, UINT32 , OPTIONAL, STATIC, AllTypes, opt_uint32, opt_int64, &AllTypes_opt_uint32_default),
PB_FIELD( 44, UINT64 , OPTIONAL, STATIC, AllTypes, opt_uint64, opt_uint32, &AllTypes_opt_uint64_default),
PB_FIELD( 45, SINT32 , OPTIONAL, STATIC, AllTypes, opt_sint32, opt_uint64, &AllTypes_opt_sint32_default),
PB_FIELD( 46, SINT64 , OPTIONAL, STATIC, AllTypes, opt_sint64, opt_sint32, &AllTypes_opt_sint64_default),
PB_FIELD( 47, BOOL , OPTIONAL, STATIC, AllTypes, opt_bool, opt_sint64, &AllTypes_opt_bool_default),
PB_FIELD( 48, FIXED32 , OPTIONAL, STATIC, AllTypes, opt_fixed32, opt_bool, &AllTypes_opt_fixed32_default),
PB_FIELD( 49, SFIXED32, OPTIONAL, STATIC, AllTypes, opt_sfixed32, opt_fixed32, &AllTypes_opt_sfixed32_default),
PB_FIELD( 50, FLOAT , OPTIONAL, STATIC, AllTypes, opt_float, opt_sfixed32, &AllTypes_opt_float_default),
PB_FIELD( 51, FIXED64 , OPTIONAL, STATIC, AllTypes, opt_fixed64, opt_float, &AllTypes_opt_fixed64_default),
PB_FIELD( 52, SFIXED64, OPTIONAL, STATIC, AllTypes, opt_sfixed64, opt_fixed64, &AllTypes_opt_sfixed64_default),
PB_FIELD( 53, DOUBLE , OPTIONAL, STATIC, AllTypes, opt_double, opt_sfixed64, &AllTypes_opt_double_default),
PB_FIELD( 54, STRING , OPTIONAL, STATIC, AllTypes, opt_string, opt_double, &AllTypes_opt_string_default),
PB_FIELD( 55, BYTES , OPTIONAL, STATIC, AllTypes, opt_bytes, opt_string, &AllTypes_opt_bytes_default),
PB_FIELD( 56, MESSAGE , OPTIONAL, STATIC, AllTypes, opt_submsg, opt_bytes, &SubMessage_fields),
PB_FIELD( 57, ENUM , OPTIONAL, STATIC, AllTypes, opt_enum, opt_submsg, &AllTypes_opt_enum_default),
PB_FIELD( 99, INT32 , REQUIRED, STATIC, AllTypes, end, opt_enum, 0),
PB_LAST_FIELD PB_LAST_FIELD
}; };
const pb_field_t Limits_fields[11] = {
PB_FIELD( 1, INT32 , REQUIRED, STATIC , FIRST, Limits, int32_min, int32_min, &Limits_int32_min_default),
PB_FIELD( 2, INT32 , REQUIRED, STATIC , OTHER, Limits, int32_max, int32_min, &Limits_int32_max_default),
PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, Limits, uint32_min, int32_max, &Limits_uint32_min_default),
PB_FIELD( 4, UINT32 , REQUIRED, STATIC , OTHER, Limits, uint32_max, uint32_min, &Limits_uint32_max_default),
PB_FIELD( 5, INT64 , REQUIRED, STATIC , OTHER, Limits, int64_min, uint32_max, &Limits_int64_min_default),
PB_FIELD( 6, INT64 , REQUIRED, STATIC , OTHER, Limits, int64_max, int64_min, &Limits_int64_max_default),
PB_FIELD( 7, UINT64 , REQUIRED, STATIC , OTHER, Limits, uint64_min, int64_max, &Limits_uint64_min_default),
PB_FIELD( 8, UINT64 , REQUIRED, STATIC , OTHER, Limits, uint64_max, uint64_min, &Limits_uint64_max_default),
PB_FIELD( 9, ENUM , REQUIRED, STATIC , OTHER, Limits, enum_min, uint64_max, &Limits_enum_min_default),
PB_FIELD( 10, ENUM , REQUIRED, STATIC , OTHER, Limits, enum_max, enum_min, &Limits_enum_max_default),
PB_LAST_FIELD
};
const pb_field_t AllTypes_fields[54] = {
PB_FIELD( 1, INT32 , REQUIRED, STATIC , FIRST, AllTypes, req_int32, req_int32, 0),
PB_FIELD( 2, INT64 , REQUIRED, STATIC , OTHER, AllTypes, req_int64, req_int32, 0),
PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, AllTypes, req_uint32, req_int64, 0),
PB_FIELD( 4, UINT64 , REQUIRED, STATIC , OTHER, AllTypes, req_uint64, req_uint32, 0),
PB_FIELD( 5, SINT32 , REQUIRED, STATIC , OTHER, AllTypes, req_sint32, req_uint64, 0),
PB_FIELD( 6, SINT64 , REQUIRED, STATIC , OTHER, AllTypes, req_sint64, req_sint32, 0),
PB_FIELD( 7, BOOL , REQUIRED, STATIC , OTHER, AllTypes, req_bool, req_sint64, 0),
PB_FIELD( 8, FIXED32 , REQUIRED, STATIC , OTHER, AllTypes, req_fixed32, req_bool, 0),
PB_FIELD( 9, SFIXED32, REQUIRED, STATIC , OTHER, AllTypes, req_sfixed32, req_fixed32, 0),
PB_FIELD( 10, FLOAT , REQUIRED, STATIC , OTHER, AllTypes, req_float, req_sfixed32, 0),
PB_FIELD( 11, FIXED64 , REQUIRED, STATIC , OTHER, AllTypes, req_fixed64, req_float, 0),
PB_FIELD( 12, SFIXED64, REQUIRED, STATIC , OTHER, AllTypes, req_sfixed64, req_fixed64, 0),
PB_FIELD( 13, DOUBLE , REQUIRED, STATIC , OTHER, AllTypes, req_double, req_sfixed64, 0),
PB_FIELD( 14, STRING , REQUIRED, STATIC , OTHER, AllTypes, req_string, req_double, 0),
PB_FIELD( 15, BYTES , REQUIRED, STATIC , OTHER, AllTypes, req_bytes, req_string, 0),
PB_FIELD( 16, MESSAGE , REQUIRED, STATIC , OTHER, AllTypes, req_submsg, req_bytes, &SubMessage_fields),
PB_FIELD( 17, ENUM , REQUIRED, STATIC , OTHER, AllTypes, req_enum, req_submsg, 0),
PB_FIELD( 21, INT32 , REPEATED, STATIC , OTHER, AllTypes, rep_int32, req_enum, 0),
PB_FIELD( 22, INT64 , REPEATED, STATIC , OTHER, AllTypes, rep_int64, rep_int32, 0),
PB_FIELD( 23, UINT32 , REPEATED, STATIC , OTHER, AllTypes, rep_uint32, rep_int64, 0),
PB_FIELD( 24, UINT64 , REPEATED, STATIC , OTHER, AllTypes, rep_uint64, rep_uint32, 0),
PB_FIELD( 25, SINT32 , REPEATED, STATIC , OTHER, AllTypes, rep_sint32, rep_uint64, 0),
PB_FIELD( 26, SINT64 , REPEATED, STATIC , OTHER, AllTypes, rep_sint64, rep_sint32, 0),
PB_FIELD( 27, BOOL , REPEATED, STATIC , OTHER, AllTypes, rep_bool, rep_sint64, 0),
PB_FIELD( 28, FIXED32 , REPEATED, STATIC , OTHER, AllTypes, rep_fixed32, rep_bool, 0),
PB_FIELD( 29, SFIXED32, REPEATED, STATIC , OTHER, AllTypes, rep_sfixed32, rep_fixed32, 0),
PB_FIELD( 30, FLOAT , REPEATED, STATIC , OTHER, AllTypes, rep_float, rep_sfixed32, 0),
PB_FIELD( 31, FIXED64 , REPEATED, STATIC , OTHER, AllTypes, rep_fixed64, rep_float, 0),
PB_FIELD( 32, SFIXED64, REPEATED, STATIC , OTHER, AllTypes, rep_sfixed64, rep_fixed64, 0),
PB_FIELD( 33, DOUBLE , REPEATED, STATIC , OTHER, AllTypes, rep_double, rep_sfixed64, 0),
PB_FIELD( 34, STRING , REPEATED, STATIC , OTHER, AllTypes, rep_string, rep_double, 0),
PB_FIELD( 35, BYTES , REPEATED, STATIC , OTHER, AllTypes, rep_bytes, rep_string, 0),
PB_FIELD( 36, MESSAGE , REPEATED, STATIC , OTHER, AllTypes, rep_submsg, rep_bytes, &SubMessage_fields),
PB_FIELD( 37, ENUM , REPEATED, STATIC , OTHER, AllTypes, rep_enum, rep_submsg, 0),
PB_FIELD( 41, INT32 , OPTIONAL, STATIC , OTHER, AllTypes, opt_int32, rep_enum, &AllTypes_opt_int32_default),
PB_FIELD( 42, INT64 , OPTIONAL, STATIC , OTHER, AllTypes, opt_int64, opt_int32, &AllTypes_opt_int64_default),
PB_FIELD( 43, UINT32 , OPTIONAL, STATIC , OTHER, AllTypes, opt_uint32, opt_int64, &AllTypes_opt_uint32_default),
PB_FIELD( 44, UINT64 , OPTIONAL, STATIC , OTHER, AllTypes, opt_uint64, opt_uint32, &AllTypes_opt_uint64_default),
PB_FIELD( 45, SINT32 , OPTIONAL, STATIC , OTHER, AllTypes, opt_sint32, opt_uint64, &AllTypes_opt_sint32_default),
PB_FIELD( 46, SINT64 , OPTIONAL, STATIC , OTHER, AllTypes, opt_sint64, opt_sint32, &AllTypes_opt_sint64_default),
PB_FIELD( 47, BOOL , OPTIONAL, STATIC , OTHER, AllTypes, opt_bool, opt_sint64, &AllTypes_opt_bool_default),
PB_FIELD( 48, FIXED32 , OPTIONAL, STATIC , OTHER, AllTypes, opt_fixed32, opt_bool, &AllTypes_opt_fixed32_default),
PB_FIELD( 49, SFIXED32, OPTIONAL, STATIC , OTHER, AllTypes, opt_sfixed32, opt_fixed32, &AllTypes_opt_sfixed32_default),
PB_FIELD( 50, FLOAT , OPTIONAL, STATIC , OTHER, AllTypes, opt_float, opt_sfixed32, &AllTypes_opt_float_default),
PB_FIELD( 51, FIXED64 , OPTIONAL, STATIC , OTHER, AllTypes, opt_fixed64, opt_float, &AllTypes_opt_fixed64_default),
PB_FIELD( 52, SFIXED64, OPTIONAL, STATIC , OTHER, AllTypes, opt_sfixed64, opt_fixed64, &AllTypes_opt_sfixed64_default),
PB_FIELD( 53, DOUBLE , OPTIONAL, STATIC , OTHER, AllTypes, opt_double, opt_sfixed64, &AllTypes_opt_double_default),
PB_FIELD( 54, STRING , OPTIONAL, STATIC , OTHER, AllTypes, opt_string, opt_double, &AllTypes_opt_string_default),
PB_FIELD( 55, BYTES , OPTIONAL, STATIC , OTHER, AllTypes, opt_bytes, opt_string, &AllTypes_opt_bytes_default),
PB_FIELD( 56, MESSAGE , OPTIONAL, STATIC , OTHER, AllTypes, opt_submsg, opt_bytes, &SubMessage_fields),
PB_FIELD( 57, ENUM , OPTIONAL, STATIC , OTHER, AllTypes, opt_enum, opt_submsg, &AllTypes_opt_enum_default),
PB_FIELD( 99, INT32 , REQUIRED, STATIC , OTHER, AllTypes, end, opt_enum, 0),
PB_FIELD(200, EXTENSION, OPTIONAL, CALLBACK, OTHER, AllTypes, extensions, end, 0),
PB_LAST_FIELD
};
/* Check that field information fits in pb_field_t */
#if !defined(PB_FIELD_32BIT)
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
* compile-time option. You can do that in pb.h or on compiler command line.
*
* The reason you need to do this is that some of your messages contain tag
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
* field descriptors.
*/
PB_STATIC_ASSERT((pb_membersize(AllTypes, req_submsg) < 65536 && pb_membersize(AllTypes, rep_submsg[0]) < 65536 && pb_membersize(AllTypes, opt_submsg) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_SubMessage_EmptyMessage_Limits_AllTypes)
#endif
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
* compile-time option. You can do that in pb.h or on compiler command line.
*
* The reason you need to do this is that some of your messages contain tag
* numbers or field sizes that are larger than what can fit in the default
* 8 bit descriptors.
*/
PB_STATIC_ASSERT((pb_membersize(AllTypes, req_submsg) < 256 && pb_membersize(AllTypes, rep_submsg[0]) < 256 && pb_membersize(AllTypes, opt_submsg) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_SubMessage_EmptyMessage_Limits_AllTypes)
#endif
/* On some platforms (such as AVR), double is really float.
* These are not directly supported by nanopb, but see example_avr_double.
* To get rid of this error, remove any double fields from your .proto.
*/
PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)

View File

@@ -1,24 +1,18 @@
/* Automatically generated nanopb header */ /* Automatically generated nanopb header */
/* Generated by nanopb-0.3.0-dev at Tue Aug 19 17:53:24 2014. */ /* This is a file generated using nanopb-0.2.0-dev.
* It is used as a part of test suite in order to detect any
* incompatible changes made to the generator in future versions.
*/
#ifndef PB_ALLTYPES_LEGACY_H_INCLUDED #ifndef _PB_ALLTYPES_PB_H_
#define PB_ALLTYPES_LEGACY_H_INCLUDED #define _PB_ALLTYPES_PB_H_
#include <pb.h> #include <pb.h>
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Enum definitions */ /* Enum definitions */
typedef enum _HugeEnum {
HugeEnum_Negative = -2147483647,
HugeEnum_Positive = 2147483647
} HugeEnum;
typedef enum _MyEnum { typedef enum _MyEnum {
MyEnum_Zero = 0, MyEnum_Zero = 0,
MyEnum_First = 1, MyEnum_First = 1,
@@ -27,23 +21,6 @@ typedef enum _MyEnum {
} MyEnum; } MyEnum;
/* Struct definitions */ /* Struct definitions */
typedef struct _EmptyMessage {
uint8_t dummy_field;
} EmptyMessage;
typedef struct _Limits {
int32_t int32_min;
int32_t int32_max;
uint32_t uint32_min;
uint32_t uint32_max;
int64_t int64_min;
int64_t int64_max;
uint64_t uint64_min;
uint64_t uint64_max;
HugeEnum enum_min;
HugeEnum enum_max;
} Limits;
typedef struct _SubMessage { typedef struct _SubMessage {
char substuff1[16]; char substuff1[16];
int32_t substuff2; int32_t substuff2;
@@ -51,11 +28,20 @@ typedef struct _SubMessage {
uint32_t substuff3; uint32_t substuff3;
} SubMessage; } SubMessage;
typedef PB_BYTES_ARRAY_T(16) AllTypes_req_bytes_t; typedef struct {
size_t size;
uint8_t bytes[16];
} AllTypes_req_bytes_t;
typedef PB_BYTES_ARRAY_T(16) AllTypes_rep_bytes_t; typedef struct {
size_t size;
uint8_t bytes[16];
} AllTypes_rep_bytes_t;
typedef PB_BYTES_ARRAY_T(16) AllTypes_opt_bytes_t; typedef struct {
size_t size;
uint8_t bytes[16];
} AllTypes_opt_bytes_t;
typedef struct _AllTypes { typedef struct _AllTypes {
int32_t req_int32; int32_t req_int32;
@@ -75,39 +61,39 @@ typedef struct _AllTypes {
AllTypes_req_bytes_t req_bytes; AllTypes_req_bytes_t req_bytes;
SubMessage req_submsg; SubMessage req_submsg;
MyEnum req_enum; MyEnum req_enum;
pb_size_t rep_int32_count; size_t rep_int32_count;
int32_t rep_int32[5]; int32_t rep_int32[5];
pb_size_t rep_int64_count; size_t rep_int64_count;
int64_t rep_int64[5]; int64_t rep_int64[5];
pb_size_t rep_uint32_count; size_t rep_uint32_count;
uint32_t rep_uint32[5]; uint32_t rep_uint32[5];
pb_size_t rep_uint64_count; size_t rep_uint64_count;
uint64_t rep_uint64[5]; uint64_t rep_uint64[5];
pb_size_t rep_sint32_count; size_t rep_sint32_count;
int32_t rep_sint32[5]; int32_t rep_sint32[5];
pb_size_t rep_sint64_count; size_t rep_sint64_count;
int64_t rep_sint64[5]; int64_t rep_sint64[5];
pb_size_t rep_bool_count; size_t rep_bool_count;
bool rep_bool[5]; bool rep_bool[5];
pb_size_t rep_fixed32_count; size_t rep_fixed32_count;
uint32_t rep_fixed32[5]; uint32_t rep_fixed32[5];
pb_size_t rep_sfixed32_count; size_t rep_sfixed32_count;
int32_t rep_sfixed32[5]; int32_t rep_sfixed32[5];
pb_size_t rep_float_count; size_t rep_float_count;
float rep_float[5]; float rep_float[5];
pb_size_t rep_fixed64_count; size_t rep_fixed64_count;
uint64_t rep_fixed64[5]; uint64_t rep_fixed64[5];
pb_size_t rep_sfixed64_count; size_t rep_sfixed64_count;
int64_t rep_sfixed64[5]; int64_t rep_sfixed64[5];
pb_size_t rep_double_count; size_t rep_double_count;
double rep_double[5]; double rep_double[5];
pb_size_t rep_string_count; size_t rep_string_count;
char rep_string[5][16]; char rep_string[5][16];
pb_size_t rep_bytes_count; size_t rep_bytes_count;
AllTypes_rep_bytes_t rep_bytes[5]; AllTypes_rep_bytes_t rep_bytes[5];
pb_size_t rep_submsg_count; size_t rep_submsg_count;
SubMessage rep_submsg[5]; SubMessage rep_submsg[5];
pb_size_t rep_enum_count; size_t rep_enum_count;
MyEnum rep_enum[5]; MyEnum rep_enum[5];
bool has_opt_int32; bool has_opt_int32;
int32_t opt_int32; int32_t opt_int32;
@@ -144,23 +130,12 @@ typedef struct _AllTypes {
bool has_opt_enum; bool has_opt_enum;
MyEnum opt_enum; MyEnum opt_enum;
int32_t end; int32_t end;
pb_extension_t *extensions;
} AllTypes; } AllTypes;
/* Default values for struct fields */ /* Default values for struct fields */
extern const char SubMessage_substuff1_default[16]; extern const char SubMessage_substuff1_default[16];
extern const int32_t SubMessage_substuff2_default; extern const int32_t SubMessage_substuff2_default;
extern const uint32_t SubMessage_substuff3_default; extern const uint32_t SubMessage_substuff3_default;
extern const int32_t Limits_int32_min_default;
extern const int32_t Limits_int32_max_default;
extern const uint32_t Limits_uint32_min_default;
extern const uint32_t Limits_uint32_max_default;
extern const int64_t Limits_int64_min_default;
extern const int64_t Limits_int64_max_default;
extern const uint64_t Limits_uint64_min_default;
extern const uint64_t Limits_uint64_max_default;
extern const HugeEnum Limits_enum_min_default;
extern const HugeEnum Limits_enum_max_default;
extern const int32_t AllTypes_opt_int32_default; extern const int32_t AllTypes_opt_int32_default;
extern const int64_t AllTypes_opt_int64_default; extern const int64_t AllTypes_opt_int64_default;
extern const uint32_t AllTypes_opt_uint32_default; extern const uint32_t AllTypes_opt_uint32_default;
@@ -178,94 +153,23 @@ extern const char AllTypes_opt_string_default[16];
extern const AllTypes_opt_bytes_t AllTypes_opt_bytes_default; extern const AllTypes_opt_bytes_t AllTypes_opt_bytes_default;
extern const MyEnum AllTypes_opt_enum_default; extern const MyEnum AllTypes_opt_enum_default;
/* Initializer values for message structs */
#define SubMessage_init_default {"1", 2, false, 3u}
#define EmptyMessage_init_default {0}
#define Limits_init_default {2147483647, -2147483647, 4294967295u, 0u, 9223372036854775807ll, -9223372036854775807ll, 18446744073709551615ull, 0ull, HugeEnum_Positive, HugeEnum_Negative}
#define AllTypes_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", {0, {0}}, SubMessage_init_default, (MyEnum)0, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {"", "", "", "", ""}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {SubMessage_init_default, SubMessage_init_default, SubMessage_init_default, SubMessage_init_default, SubMessage_init_default}, 0, {(MyEnum)0, (MyEnum)0, (MyEnum)0, (MyEnum)0, (MyEnum)0}, false, 4041, false, 4042ll, false, 4043u, false, 4044ull, false, 4045, false, 4046, false, false, false, 4048u, false, 4049, false, 4050, false, 4051ull, false, 4052ll, false, 4053, false, "4054", false, {4, {0x34,0x30,0x35,0x35}}, false, SubMessage_init_default, false, MyEnum_Second, 0, NULL}
#define SubMessage_init_zero {"", 0, false, 0}
#define EmptyMessage_init_zero {0}
#define Limits_init_zero {0, 0, 0, 0, 0, 0, 0, 0, (HugeEnum)0, (HugeEnum)0}
#define AllTypes_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", {0, {0}}, SubMessage_init_zero, (MyEnum)0, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {"", "", "", "", ""}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {SubMessage_init_zero, SubMessage_init_zero, SubMessage_init_zero, SubMessage_init_zero, SubMessage_init_zero}, 0, {(MyEnum)0, (MyEnum)0, (MyEnum)0, (MyEnum)0, (MyEnum)0}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, "", false, {0, {0}}, false, SubMessage_init_zero, false, (MyEnum)0, 0, NULL}
/* Field tags (for use in manual encoding/decoding) */
#define Limits_int32_min_tag 1
#define Limits_int32_max_tag 2
#define Limits_uint32_min_tag 3
#define Limits_uint32_max_tag 4
#define Limits_int64_min_tag 5
#define Limits_int64_max_tag 6
#define Limits_uint64_min_tag 7
#define Limits_uint64_max_tag 8
#define Limits_enum_min_tag 9
#define Limits_enum_max_tag 10
#define SubMessage_substuff1_tag 1
#define SubMessage_substuff2_tag 2
#define SubMessage_substuff3_tag 3
#define AllTypes_req_int32_tag 1
#define AllTypes_req_int64_tag 2
#define AllTypes_req_uint32_tag 3
#define AllTypes_req_uint64_tag 4
#define AllTypes_req_sint32_tag 5
#define AllTypes_req_sint64_tag 6
#define AllTypes_req_bool_tag 7
#define AllTypes_req_fixed32_tag 8
#define AllTypes_req_sfixed32_tag 9
#define AllTypes_req_float_tag 10
#define AllTypes_req_fixed64_tag 11
#define AllTypes_req_sfixed64_tag 12
#define AllTypes_req_double_tag 13
#define AllTypes_req_string_tag 14
#define AllTypes_req_bytes_tag 15
#define AllTypes_req_submsg_tag 16
#define AllTypes_req_enum_tag 17
#define AllTypes_rep_int32_tag 21
#define AllTypes_rep_int64_tag 22
#define AllTypes_rep_uint32_tag 23
#define AllTypes_rep_uint64_tag 24
#define AllTypes_rep_sint32_tag 25
#define AllTypes_rep_sint64_tag 26
#define AllTypes_rep_bool_tag 27
#define AllTypes_rep_fixed32_tag 28
#define AllTypes_rep_sfixed32_tag 29
#define AllTypes_rep_float_tag 30
#define AllTypes_rep_fixed64_tag 31
#define AllTypes_rep_sfixed64_tag 32
#define AllTypes_rep_double_tag 33
#define AllTypes_rep_string_tag 34
#define AllTypes_rep_bytes_tag 35
#define AllTypes_rep_submsg_tag 36
#define AllTypes_rep_enum_tag 37
#define AllTypes_opt_int32_tag 41
#define AllTypes_opt_int64_tag 42
#define AllTypes_opt_uint32_tag 43
#define AllTypes_opt_uint64_tag 44
#define AllTypes_opt_sint32_tag 45
#define AllTypes_opt_sint64_tag 46
#define AllTypes_opt_bool_tag 47
#define AllTypes_opt_fixed32_tag 48
#define AllTypes_opt_sfixed32_tag 49
#define AllTypes_opt_float_tag 50
#define AllTypes_opt_fixed64_tag 51
#define AllTypes_opt_sfixed64_tag 52
#define AllTypes_opt_double_tag 53
#define AllTypes_opt_string_tag 54
#define AllTypes_opt_bytes_tag 55
#define AllTypes_opt_submsg_tag 56
#define AllTypes_opt_enum_tag 57
#define AllTypes_end_tag 99
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
extern const pb_field_t SubMessage_fields[4]; extern const pb_field_t SubMessage_fields[4];
extern const pb_field_t EmptyMessage_fields[1]; extern const pb_field_t AllTypes_fields[53];
extern const pb_field_t Limits_fields[11];
extern const pb_field_t AllTypes_fields[54];
/* Maximum encoded size of messages (where known) */ /* Check that field information fits in pb_field_t */
#define SubMessage_size 34 #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
#define EmptyMessage_size 0 STATIC_ASSERT((pb_membersize(AllTypes, req_submsg) < 256 && pb_membersize(AllTypes, rep_submsg[0]) < 256 && pb_membersize(AllTypes, opt_submsg) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_SubMessage_AllTypes)
#define Limits_size 90 #endif
#define AllTypes_size 1362
#if !defined(PB_FIELD_32BIT)
STATIC_ASSERT((pb_membersize(AllTypes, req_submsg) < 65536 && pb_membersize(AllTypes, rep_submsg[0]) < 65536 && pb_membersize(AllTypes, opt_submsg) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_SubMessage_AllTypes)
#endif
/* On some platforms (such as AVR), double is really float.
* These are not directly supported by nanopb, but see example_avr_double.
*/
STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -1,3 +0,0 @@
* max_size:16
* max_count:5

View File

@@ -1,108 +0,0 @@
message SubMessage {
required string substuff1 = 1 [default = "1"];
required int32 substuff2 = 2 [default = 2];
optional fixed32 substuff3 = 3 [default = 3];
}
message EmptyMessage {
}
enum HugeEnum {
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
required int32 int32_min = 1 [default = 2147483647];
required int32 int32_max = 2 [default = -2147483647];
required uint32 uint32_min = 3 [default = 4294967295];
required uint32 uint32_max = 4 [default = 0];
required int64 int64_min = 5 [default = 9223372036854775807];
required int64 int64_max = 6 [default = -9223372036854775807];
required uint64 uint64_min = 7 [default = 18446744073709551615];
required uint64 uint64_max = 8 [default = 0];
required HugeEnum enum_min = 9 [default = Positive];
required HugeEnum enum_max = 10 [default = Negative];
}
enum MyEnum {
Zero = 0;
First = 1;
Second = 2;
Truth = 42;
}
message AllTypes {
required int32 req_int32 = 1;
required int64 req_int64 = 2;
required uint32 req_uint32 = 3;
required uint64 req_uint64 = 4;
required sint32 req_sint32 = 5;
required sint64 req_sint64 = 6;
required bool req_bool = 7;
required fixed32 req_fixed32 = 8;
required sfixed32 req_sfixed32= 9;
required float req_float = 10;
required fixed64 req_fixed64 = 11;
required sfixed64 req_sfixed64= 12;
required double req_double = 13;
required string req_string = 14;
required bytes req_bytes = 15;
required SubMessage req_submsg = 16;
required MyEnum req_enum = 17;
repeated int32 rep_int32 = 21 [packed = true];
repeated int64 rep_int64 = 22 [packed = true];
repeated uint32 rep_uint32 = 23 [packed = true];
repeated uint64 rep_uint64 = 24 [packed = true];
repeated sint32 rep_sint32 = 25 [packed = true];
repeated sint64 rep_sint64 = 26 [packed = true];
repeated bool rep_bool = 27 [packed = true];
repeated fixed32 rep_fixed32 = 28 [packed = true];
repeated sfixed32 rep_sfixed32= 29 [packed = true];
repeated float rep_float = 30 [packed = true];
repeated fixed64 rep_fixed64 = 31 [packed = true];
repeated sfixed64 rep_sfixed64= 32 [packed = true];
repeated double rep_double = 33 [packed = true];
repeated string rep_string = 34;
repeated bytes rep_bytes = 35;
repeated SubMessage rep_submsg = 36;
repeated MyEnum rep_enum = 37 [packed = true];
optional int32 opt_int32 = 41 [default = 4041];
optional int64 opt_int64 = 42 [default = 4042];
optional uint32 opt_uint32 = 43 [default = 4043];
optional uint64 opt_uint64 = 44 [default = 4044];
optional sint32 opt_sint32 = 45 [default = 4045];
optional sint64 opt_sint64 = 46 [default = 4046];
optional bool opt_bool = 47 [default = false];
optional fixed32 opt_fixed32 = 48 [default = 4048];
optional sfixed32 opt_sfixed32= 49 [default = 4049];
optional float opt_float = 50 [default = 4050];
optional fixed64 opt_fixed64 = 51 [default = 4051];
optional sfixed64 opt_sfixed64= 52 [default = 4052];
optional double opt_double = 53 [default = 4053];
optional string opt_string = 54 [default = "4054"];
optional bytes opt_bytes = 55 [default = "4055"];
optional SubMessage opt_submsg = 56;
optional MyEnum opt_enum = 57 [default = Second];
// Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 99;
extensions 200 to 255;
}

View File

@@ -22,7 +22,10 @@
the decoding and checks the fields. */ the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode) bool check_alltypes(pb_istream_t *stream, int mode)
{ {
AllTypes alltypes = {0}; AllTypes alltypes;
/* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes));
if (!pb_decode(stream, AllTypes_fields, &alltypes)) if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false; return false;

View File

@@ -2,8 +2,8 @@
Import("env") Import("env")
enc = env.Program(["encode_buffer.c", "$COMMON/person.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_buffer.c", "$COMMON/person.pb.c", "$COMMON/pb_encode.o"])
dec = env.Program(["decode_buffer.c", "$COMMON/person.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = env.Program(["decode_buffer.c", "$COMMON/person.pb.c", "$COMMON/pb_decode.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_buffer.output"]) env.RunTest([dec, "encode_buffer.output"])

View File

@@ -2,8 +2,8 @@
Import("env") Import("env")
enc = env.Program(["encode_stream.c", "$COMMON/person.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_stream.c", "$COMMON/person.pb.c", "$COMMON/pb_encode.o"])
dec = env.Program(["decode_stream.c", "$COMMON/person.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = env.Program(["decode_stream.c", "$COMMON/person.pb.c", "$COMMON/pb_decode.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_stream.output"]) env.RunTest([dec, "encode_stream.output"])

View File

@@ -18,11 +18,10 @@ strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS']) strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_bufonly.o", "$NANOPB/pb_decode.c") strict.Object("pb_decode_bufonly.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_bufonly.o", "$NANOPB/pb_encode.c") strict.Object("pb_encode_bufonly.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common_bufonly.o", "$NANOPB/pb_common.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_bufonly.o", "pb_common_bufonly.o"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_bufonly.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_bufonly.o", "pb_common_bufonly.o"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_bufonly.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -3,8 +3,8 @@
Import("env") Import("env")
env.NanopbProto("callbacks") env.NanopbProto("callbacks")
enc = env.Program(["encode_callbacks.c", "callbacks.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_callbacks.c", "callbacks.pb.c", "$COMMON/pb_encode.o"])
dec = env.Program(["decode_callbacks.c", "callbacks.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = env.Program(["decode_callbacks.c", "callbacks.pb.c", "$COMMON/pb_decode.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_callbacks.output"]) env.RunTest([dec, "encode_callbacks.output"])

View File

@@ -8,41 +8,10 @@ env.NanopbProto("unittestproto")
# Protocol definitions for basic_buffer/stream tests # Protocol definitions for basic_buffer/stream tests
env.NanopbProto("person") env.NanopbProto("person")
#--------------------------------------------
# Binaries of the pb_decode.c and pb_encode.c # Binaries of the pb_decode.c and pb_encode.c
# These are built using more strict warning flags. # These are built using more strict warning flags.
strict = env.Clone() strict = env.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS']) strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode.o", "$NANOPB/pb_decode.c") strict.Object("pb_decode.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode.o", "$NANOPB/pb_encode.c") strict.Object("pb_encode.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common.o", "$NANOPB/pb_common.c")
#-----------------------------------------------
# Binaries of pb_decode etc. with malloc support
# Uses malloc_wrappers.c to count allocations.
malloc_env = env.Clone()
malloc_env.Append(CPPDEFINES = {'PB_ENABLE_MALLOC': 1,
'PB_SYSTEM_HEADER': '\\"malloc_wrappers_syshdr.h\\"'})
malloc_env.Append(CPPPATH = ["$COMMON"])
if 'SYSHDR' in malloc_env:
malloc_env.Append(CPPDEFINES = {'PB_OLD_SYSHDR': malloc_env['SYSHDR']})
# Disable libmudflap, because it will confuse valgrind
# and other memory leak detection tools.
if '-fmudflap' in env["CCFLAGS"]:
malloc_env["CCFLAGS"].remove("-fmudflap")
malloc_env["LINKFLAGS"].remove("-fmudflap")
malloc_env["LIBS"].remove("mudflap")
malloc_strict = malloc_env.Clone()
malloc_strict.Append(CFLAGS = malloc_strict['CORECFLAGS'])
malloc_strict.Object("pb_decode_with_malloc.o", "$NANOPB/pb_decode.c")
malloc_strict.Object("pb_encode_with_malloc.o", "$NANOPB/pb_encode.c")
malloc_strict.Object("pb_common_with_malloc.o", "$NANOPB/pb_common.c")
malloc_env.Object("malloc_wrappers.o", "malloc_wrappers.c")
malloc_env.Depends("$NANOPB/pb.h", ["malloc_wrappers_syshdr.h", "malloc_wrappers.h"])
Export("malloc_env")

View File

@@ -34,8 +34,3 @@ message CallbackContainer {
message CallbackContainerContainer { message CallbackContainerContainer {
required CallbackContainer submsg = 1; required CallbackContainer submsg = 1;
} }
message StringPointerContainer {
repeated string rep_str = 1 [(nanopb).type = FT_POINTER];
}

View File

@@ -11,15 +11,14 @@ env.Append(CPPDEFINES = ['__STDC_LIMIT_MACROS'])
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.cxx", "#../pb_encode.c", c) env.Command("pb_encode.cxx", "#../pb_encode.c", c)
env.Command("pb_decode.cxx", "#../pb_decode.c", c) env.Command("pb_decode.cxx", "#../pb_decode.c", c)
env.Command("pb_common.cxx", "#../pb_common.c", c)
env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c) env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c)
env.Command("alltypes.pb.cxx", "$BUILD/alltypes/alltypes.pb.c", c) env.Command("alltypes.pb.cxx", "$BUILD/alltypes/alltypes.pb.c", c)
env.Command("encode_alltypes.cxx", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.cxx", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.cxx", "$BUILD/alltypes/decode_alltypes.c", c) env.Command("decode_alltypes.cxx", "$BUILD/alltypes/decode_alltypes.c", c)
# Now build and run the test normally. # Now build and run the test normally.
enc = env.Program(["encode_alltypes.cxx", "alltypes.pb.cxx", "pb_encode.cxx", "pb_common.cxx"]) enc = env.Program(["encode_alltypes.cxx", "alltypes.pb.cxx", "pb_encode.cxx"])
dec = env.Program(["decode_alltypes.cxx", "alltypes.pb.cxx", "pb_decode.cxx", "pb_common.cxx"]) dec = env.Program(["decode_alltypes.cxx", "alltypes.pb.cxx", "pb_decode.cxx"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -1,11 +0,0 @@
Import("env")
# Encode cyclic messages with callback fields
c = Copy("$TARGET", "$SOURCE")
env.Command("cyclic_callback.proto", "cyclic.proto", c)
env.NanopbProto(["cyclic_callback", "cyclic_callback.options"])
enc_callback = env.Program(["encode_cyclic_callback.c", "cyclic_callback.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])

View File

@@ -1,25 +0,0 @@
// Test structures with cyclic references.
// These can only be handled in pointer/callback mode,
// see associated .options files.
message TreeNode
{
optional int32 leaf = 1;
optional TreeNode left = 2;
optional TreeNode right = 3;
}
message Dictionary
{
repeated KeyValuePair dictItem = 1;
}
message KeyValuePair
{
required string key = 1;
optional string stringValue = 2;
optional int32 intValue = 3;
optional Dictionary dictValue = 4;
optional TreeNode treeValue = 5;
}

View File

@@ -1,7 +0,0 @@
TreeNode.left type:FT_CALLBACK
TreeNode.right type:FT_CALLBACK
Dictionary.data type:FT_CALLBACK
KeyValuePair.key max_size:8
KeyValuePair.stringValue max_size:8
KeyValuePair.treeValue type:FT_CALLBACK

View File

@@ -1,148 +0,0 @@
/* This program parses an input string in a format a bit like JSON:
* {'foobar': 1234, 'xyz': 'abc', 'tree': [[[1, 2], 3], [4, 5]]}
* and encodes it as protobuf
*
* Note: The string parsing here is not in any way intended to be robust
* nor safe against buffer overflows. It is just for this test.
*/
#include <pb_encode.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cyclic_callback.pb.h"
static char *find_end_of_item(char *p)
{
int depth = 0;
do {
if (*p == '[' || *p == '{') depth++;
if (*p == ']' || *p == '}') depth--;
p++;
} while (depth > 0 || (*p != ',' && *p != '}'));
if (*p == '}')
return p; /* End of parent dict */
p++;
while (*p == ' ') p++;
return p;
}
/* Parse a tree in format [[1 2] 3] and encode it directly to protobuf */
static bool encode_tree(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
TreeNode tree = TreeNode_init_zero;
char *p = (char*)*arg;
if (*p == '[')
{
/* This is a tree branch */
p++;
tree.left.funcs.encode = encode_tree;
tree.left.arg = p;
p = find_end_of_item(p);
tree.right.funcs.encode = encode_tree;
tree.right.arg = p;
}
else
{
/* This is a leaf node */
tree.has_leaf = true;
tree.leaf = atoi(p);
}
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, TreeNode_fields, &tree);
}
/* Parse a dictionary in format {'name': value} and encode it directly to protobuf */
static bool encode_dictionary(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
int textlen;
char *p = (char*)*arg;
if (*p == '{') p++;
while (*p != '}')
{
KeyValuePair pair = KeyValuePair_init_zero;
if (*p != '\'')
PB_RETURN_ERROR(stream, "invalid key, missing quote");
p++; /* Starting quote of key */
textlen = strchr(p, '\'') - p;
strncpy(pair.key, p, textlen);
pair.key[textlen] = 0;
p += textlen + 2;
while (*p == ' ') p++;
if (*p == '[')
{
/* Value is a tree */
pair.treeValue.funcs.encode = encode_tree;
pair.treeValue.arg = p;
}
else if (*p == '\'')
{
/* Value is a string */
pair.has_stringValue = true;
p++;
textlen = strchr(p, '\'') - p;
strncpy(pair.stringValue, p, textlen);
pair.stringValue[textlen] = 0;
}
else if (*p == '{')
{
/* Value is a dictionary */
pair.has_dictValue = true;
pair.dictValue.dictItem.funcs.encode = encode_dictionary;
pair.dictValue.dictItem.arg = p;
}
else
{
/* Value is integer */
pair.has_intValue = true;
pair.intValue = atoi(p);
}
p = find_end_of_item(p);
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!pb_encode_submessage(stream, KeyValuePair_fields, &pair))
return false;
}
return true;
}
int main(int argc, char *argv[])
{
uint8_t buffer[256];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
Dictionary dict = Dictionary_init_zero;
if (argc <= 1)
{
fprintf(stderr, "Usage: %s \"{'foobar': 1234, ...}\"\n", argv[0]);
return 1;
}
dict.dictItem.funcs.encode = encode_dictionary;
dict.dictItem.arg = argv[1];
if (!pb_encode(&stream, Dictionary_fields, &dict))
{
fprintf(stderr, "Encoding error: %s\n", PB_GET_ERROR(&stream));
return 1;
}
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0;
}

View File

@@ -1,6 +1,5 @@
/* This includes the whole .c file to get access to static functions. */ /* This includes the whole .c file to get access to static functions. */
#define PB_ENABLE_MALLOC #define PB_ENABLE_MALLOC
#include "pb_common.c"
#include "pb_decode.c" #include "pb_decode.c"
#include <stdio.h> #include <stdio.h>
@@ -87,20 +86,6 @@ int main()
pb_decode_varint(&s, (uint64_t*)&i) && i == -1)); pb_decode_varint(&s, (uint64_t*)&i) && i == -1));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
pb_decode_varint(&s, &u) && u == UINT64_MAX)); pb_decode_varint(&s, &u) && u == UINT64_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
!pb_decode_varint(&s, &u)));
}
{
pb_istream_t s;
uint32_t u;
COMMENT("Test pb_decode_varint32");
TEST((s = S("\x00"), pb_decode_varint32(&s, &u) && u == 0));
TEST((s = S("\x01"), pb_decode_varint32(&s, &u) && u == 1));
TEST((s = S("\xAC\x02"), pb_decode_varint32(&s, &u) && u == 300));
TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint32(&s, &u) && u == UINT32_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\x01"), !pb_decode_varint32(&s, &u)));
} }
{ {
@@ -123,16 +108,16 @@ int main()
} }
{ {
pb_istream_t s = S("\x01\x00"); pb_istream_t s = S("\x01\xFF\xFF\x03");
pb_field_t f = {1, PB_LTYPE_VARINT, 0, 0, 4, 0, 0}; pb_field_t f = {1, PB_LTYPE_VARINT, 0, 0, 4, 0, 0};
uint32_t d; uint32_t d;
COMMENT("Test pb_dec_varint using uint32_t") COMMENT("Test pb_dec_varint using uint32_t")
TEST(pb_dec_varint(&s, &f, &d) && d == 1) TEST(pb_dec_varint(&s, &f, &d) && d == 1)
/* Verify that no more than data_size is written. */ /* Verify that no more than data_size is written. */
d = 0xFFFFFFFF; d = 0;
f.data_size = 1; f.data_size = 1;
TEST(pb_dec_varint(&s, &f, &d) && (d == 0xFFFFFF00 || d == 0x00FFFFFF)) TEST(pb_dec_varint(&s, &f, &d) && (d == 0xFF || d == 0xFF000000))
} }
{ {
@@ -184,7 +169,7 @@ int main()
{ {
pb_istream_t s; pb_istream_t s;
struct { pb_size_t size; uint8_t bytes[5]; } d; struct { size_t size; uint8_t bytes[5]; } d;
pb_field_t f = {1, PB_LTYPE_BYTES, 0, 0, sizeof(d), 0, 0}; pb_field_t f = {1, PB_LTYPE_BYTES, 0, 0, sizeof(d), 0, 0};
COMMENT("Test pb_dec_bytes") COMMENT("Test pb_dec_bytes")
@@ -265,7 +250,7 @@ int main()
{ {
pb_istream_t s; pb_istream_t s;
CallbackArray dest; CallbackArray dest;
struct { pb_size_t size; uint8_t bytes[10]; } ref; struct { size_t size; uint8_t bytes[10]; } ref;
dest.data.funcs.decode = &callback_check; dest.data.funcs.decode = &callback_check;
dest.data.arg = &ref; dest.data.arg = &ref;

View File

@@ -1,5 +1,4 @@
/* This includes the whole .c file to get access to static functions. */ /* This includes the whole .c file to get access to static functions. */
#include "pb_common.c"
#include "pb_encode.c" #include "pb_encode.c"
#include <stdio.h> #include <stdio.h>
@@ -170,7 +169,7 @@ int main()
{ {
uint8_t buffer[30]; uint8_t buffer[30];
pb_ostream_t s; pb_ostream_t s;
struct { pb_size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}}; struct { size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}};
COMMENT("Test pb_enc_bytes") COMMENT("Test pb_enc_bytes")
TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x05xyzzy")) TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x05xyzzy"))
@@ -331,23 +330,6 @@ int main()
TEST(s.bytes_written == StringMessage_size); TEST(s.bytes_written == StringMessage_size);
} }
{
uint8_t buffer[128];
pb_ostream_t s;
StringPointerContainer msg = StringPointerContainer_init_zero;
char *strs[1] = {NULL};
char zstr[] = "Z";
COMMENT("Test string pointer encoding.");
msg.rep_str = strs;
msg.rep_str_count = 1;
TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x00"))
strs[0] = zstr;
TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x01Z"))
}
if (status != 0) if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n"); fprintf(stdout, "\n\nSome tests FAILED!\n");

View File

@@ -8,8 +8,8 @@ incpath.Append(PROTOCPATH = '$BUILD/alltypes')
incpath.Append(CPPPATH = '$BUILD/alltypes') incpath.Append(CPPPATH = '$BUILD/alltypes')
incpath.NanopbProto(["extensions", "extensions.options"]) incpath.NanopbProto(["extensions", "extensions.options"])
enc = incpath.Program(["encode_extensions.c", "extensions.pb.c", "$BUILD/alltypes/alltypes.pb$OBJSUFFIX", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = incpath.Program(["encode_extensions.c", "extensions.pb.c", "$BUILD/alltypes/alltypes.pb$OBJSUFFIX", "$COMMON/pb_encode.o"])
dec = incpath.Program(["decode_extensions.c", "extensions.pb.c", "$BUILD/alltypes/alltypes.pb$OBJSUFFIX", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) dec = incpath.Program(["decode_extensions.c", "extensions.pb.c", "$BUILD/alltypes/alltypes.pb$OBJSUFFIX", "$COMMON/pb_decode.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_extensions.output"]) env.RunTest([dec, "encode_extensions.output"])

View File

@@ -7,8 +7,8 @@ extend AllTypes {
message ExtensionMessage { message ExtensionMessage {
extend AllTypes { extend AllTypes {
optional ExtensionMessage AllTypes_extensionfield2 = 254; optional ExtensionMessage AllTypes_extensionfield2 = 254;
// required ExtensionMessage AllTypes_extensionfield3 = 253; // No longer allowed by protobuf 3 required ExtensionMessage AllTypes_extensionfield3 = 253;
repeated ExtensionMessage AllTypes_extensionfield4 = 252; repeated ExtensionMessage AllTypes_extensionfield4 = 252;
} }
required string test1 = 1; required string test1 = 1;

View File

@@ -19,11 +19,10 @@ strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS']) strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_fields16.o", "$NANOPB/pb_decode.c") strict.Object("pb_decode_fields16.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_fields16.o", "$NANOPB/pb_encode.c") strict.Object("pb_encode_fields16.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common_fields16.o", "$NANOPB/pb_common.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_fields16.o", "pb_common_fields16.o"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_fields16.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_fields16.o", "pb_common_fields16.o"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_fields16.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -101,12 +101,6 @@ message AllTypes {
optional MyEnum opt_enum = 10057 [default = Second]; optional MyEnum opt_enum = 10057 [default = Second];
optional EmptyMessage opt_emptymsg = 10058; optional EmptyMessage opt_emptymsg = 10058;
oneof oneof
{
SubMessage oneof_msg1 = 10059;
EmptyMessage oneof_msg2 = 10060;
}
// Check that extreme integer values are handled correctly // Check that extreme integer values are handled correctly
required Limits req_limits = 98; required Limits req_limits = 98;

View File

@@ -19,11 +19,10 @@ strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS']) strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_fields32.o", "$NANOPB/pb_decode.c") strict.Object("pb_decode_fields32.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_fields32.o", "$NANOPB/pb_encode.c") strict.Object("pb_encode_fields32.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common_fields32.o", "$NANOPB/pb_common.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_fields32.o", "pb_common_fields32.o"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_fields32.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_fields32.o", "pb_common_fields32.o"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_fields32.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -101,12 +101,6 @@ message AllTypes {
optional MyEnum opt_enum = 10057 [default = Second]; optional MyEnum opt_enum = 10057 [default = Second];
optional EmptyMessage opt_emptymsg = 10058; optional EmptyMessage opt_emptymsg = 10058;
oneof oneof
{
SubMessage oneof_msg1 = 10059;
EmptyMessage oneof_msg2 = 10060;
}
// Check that extreme integer values are handled correctly // Check that extreme integer values are handled correctly
required Limits req_limits = 98; required Limits req_limits = 98;

View File

@@ -1,9 +1,29 @@
# Run a fuzz test to verify robustness against corrupted/malicious data. # Run a fuzz test to verify robustness against corrupted/malicious data.
Import("env", "malloc_env") Import("env")
# We need our own pb_decode.o for the malloc support
env = env.Clone()
env.Append(CPPDEFINES = {'PB_ENABLE_MALLOC': 1,
'PB_SYSTEM_HEADER': '\\"fuzz_syshdr.h\\"'})
env.Append(CPPPATH = ".")
if 'SYSHDR' in env:
env.Append(CPPDEFINES = {'PB_OLD_SYSHDR': env['SYSHDR']})
# Disable libmudflap, because it will confuse valgrind
# and other memory leak detection tools.
if '-fmudflap' in env["CCFLAGS"]:
env["CCFLAGS"].remove("-fmudflap")
env["LINKFLAGS"].remove("-fmudflap")
env["LIBS"].remove("mudflap")
strict = env.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_with_malloc.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_with_malloc.o", "$NANOPB/pb_encode.c")
# We want both pointer and static versions of the AllTypes message # We want both pointer and static versions of the AllTypes message
# Prefix them with package name.
env.Command("alltypes_static.proto", "#alltypes/alltypes.proto", env.Command("alltypes_static.proto", "#alltypes/alltypes.proto",
lambda target, source, env: lambda target, source, env:
open(str(target[0]), 'w').write("package alltypes_static;\n" open(str(target[0]), 'w').write("package alltypes_static;\n"
@@ -15,22 +35,21 @@ env.Command("alltypes_pointer.proto", "#alltypes/alltypes.proto",
p1 = env.NanopbProto(["alltypes_pointer", "alltypes_pointer.options"]) p1 = env.NanopbProto(["alltypes_pointer", "alltypes_pointer.options"])
p2 = env.NanopbProto(["alltypes_static", "alltypes_static.options"]) p2 = env.NanopbProto(["alltypes_static", "alltypes_static.options"])
fuzz = malloc_env.Program(["fuzztest.c", fuzz = env.Program(["fuzztest.c",
"alltypes_pointer.pb.c", "alltypes_pointer.pb.c",
"alltypes_static.pb.c", "alltypes_static.pb.c",
"$COMMON/pb_encode_with_malloc.o", "pb_encode_with_malloc.o",
"$COMMON/pb_decode_with_malloc.o", "pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o", "malloc_wrappers.c"])
"$COMMON/malloc_wrappers.o"]) Depends([p1, p2, fuzz], ["fuzz_syshdr.h", "malloc_wrappers.h"])
env.RunTest(fuzz) env.RunTest(fuzz)
fuzzstub = malloc_env.Program(["fuzzstub.c", fuzzstub = env.Program(["fuzzstub.c",
"alltypes_pointer.pb.c", "alltypes_pointer.pb.c",
"alltypes_static.pb.c", "alltypes_static.pb.c",
"$COMMON/pb_encode_with_malloc.o", "pb_encode_with_malloc.o",
"$COMMON/pb_decode_with_malloc.o", "pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o", "malloc_wrappers.c"])
"$COMMON/malloc_wrappers.o"])

View File

@@ -10,7 +10,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <malloc_wrappers.h> #include "malloc_wrappers.h"
#include "alltypes_static.pb.h" #include "alltypes_static.pb.h"
#include "alltypes_pointer.pb.h" #include "alltypes_pointer.pb.h"

View File

@@ -9,7 +9,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <malloc_wrappers.h> #include "malloc_wrappers.h"
#include "alltypes_static.pb.h" #include "alltypes_static.pb.h"
#include "alltypes_pointer.pb.h" #include "alltypes_pointer.pb.h"

View File

@@ -1,12 +0,0 @@
# Test that the int_size option in .proto works.
Import('env')
env.NanopbProto('intsizes')
p = env.Program(["intsizes_unittests.c",
"intsizes.pb.c",
"$COMMON/pb_encode.o",
"$COMMON/pb_decode.o",
"$COMMON/pb_common.o"])
env.RunTest(p)

View File

@@ -1,39 +0,0 @@
/* Test the integer size overriding in nanopb options.
* This allows to use 8- and 16-bit integer variables, which are not supported
* directly by Google Protobuf.
*
* The int_size setting will override the number of bits, but keep the type
* otherwise. E.g. uint32 + IS_8 => uint8_t
*/
import 'nanopb.proto';
message IntSizes {
required int32 req_int8 = 1 [(nanopb).int_size = IS_8];
required uint32 req_uint8 = 2 [(nanopb).int_size = IS_8];
required sint32 req_sint8 = 3 [(nanopb).int_size = IS_8];
required int32 req_int16 = 4 [(nanopb).int_size = IS_16];
required uint32 req_uint16 = 5 [(nanopb).int_size = IS_16];
required sint32 req_sint16 = 6 [(nanopb).int_size = IS_16];
required int32 req_int32 = 7 [(nanopb).int_size = IS_32];
required uint32 req_uint32 = 8 [(nanopb).int_size = IS_32];
required sint32 req_sint32 = 9 [(nanopb).int_size = IS_32];
required int32 req_int64 = 10 [(nanopb).int_size = IS_64];
required uint32 req_uint64 = 11 [(nanopb).int_size = IS_64];
required sint32 req_sint64 = 12 [(nanopb).int_size = IS_64];
}
message DefaultSizes {
required int32 req_int8 = 1 ;
required uint32 req_uint8 = 2 ;
required sint32 req_sint8 = 3 ;
required int32 req_int16 = 4 ;
required uint32 req_uint16 = 5 ;
required sint32 req_sint16 = 6 ;
required int32 req_int32 = 7 ;
required uint32 req_uint32 = 8 ;
required sint32 req_sint32 = 9 ;
required int64 req_int64 = 10;
required uint64 req_uint64 = 11;
required sint64 req_sint64 = 12;
}

View File

@@ -1,122 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <pb_decode.h>
#include <pb_encode.h>
#include "unittests.h"
#include "intsizes.pb.h"
#define S(x) pb_istream_from_buffer((uint8_t*)x, sizeof(x) - 1)
/* This is a macro instead of function in order to get the actual values
* into the TEST() lines in output */
#define TEST_ROUNDTRIP(int8, uint8, sint8, \
int16, uint16, sint16, \
int32, uint32, sint32, \
int64, uint64, sint64, expected_result) \
{ \
uint8_t buffer1[128], buffer2[128]; \
size_t msgsize; \
DefaultSizes msg1 = DefaultSizes_init_zero; \
IntSizes msg2 = IntSizes_init_zero; \
\
msg1.req_int8 = int8; \
msg1.req_uint8 = uint8; \
msg1.req_sint8 = sint8; \
msg1.req_int16 = int16; \
msg1.req_uint16 = uint16; \
msg1.req_sint16 = sint16; \
msg1.req_int32 = int32; \
msg1.req_uint32 = uint32; \
msg1.req_sint32 = sint32; \
msg1.req_int64 = int64; \
msg1.req_uint64 = uint64; \
msg1.req_sint64 = sint64; \
\
{ \
pb_ostream_t s = pb_ostream_from_buffer(buffer1, sizeof(buffer1)); \
TEST(pb_encode(&s, DefaultSizes_fields, &msg1)); \
msgsize = s.bytes_written; \
} \
\
{ \
pb_istream_t s = pb_istream_from_buffer(buffer1, msgsize); \
TEST(pb_decode(&s, IntSizes_fields, &msg2) == expected_result); \
if (expected_result) \
{ \
TEST( (int64_t)msg2.req_int8 == int8); \
TEST((uint64_t)msg2.req_uint8 == uint8); \
TEST( (int64_t)msg2.req_sint8 == sint8); \
TEST( (int64_t)msg2.req_int16 == int16); \
TEST((uint64_t)msg2.req_uint16 == uint16); \
TEST( (int64_t)msg2.req_sint16 == sint16); \
TEST( (int64_t)msg2.req_int32 == int32); \
TEST((uint64_t)msg2.req_uint32 == uint32); \
TEST( (int64_t)msg2.req_sint32 == sint32); \
TEST( (int64_t)msg2.req_int64 == int64); \
TEST((uint64_t)msg2.req_uint64 == uint64); \
TEST( (int64_t)msg2.req_sint64 == sint64); \
} \
} \
\
if (expected_result) \
{ \
pb_ostream_t s = pb_ostream_from_buffer(buffer2, sizeof(buffer2)); \
TEST(pb_encode(&s, IntSizes_fields, &msg2)); \
TEST(s.bytes_written == msgsize); \
TEST(memcmp(buffer1, buffer2, msgsize) == 0); \
} \
}
int main()
{
int status = 0;
{
IntSizes msg = IntSizes_init_zero;
COMMENT("Test field sizes");
TEST(sizeof(msg.req_int8) == 1);
TEST(sizeof(msg.req_uint8) == 1);
TEST(sizeof(msg.req_sint8) == 1);
TEST(sizeof(msg.req_int16) == 2);
TEST(sizeof(msg.req_uint16) == 2);
TEST(sizeof(msg.req_sint16) == 2);
TEST(sizeof(msg.req_int32) == 4);
TEST(sizeof(msg.req_uint32) == 4);
TEST(sizeof(msg.req_sint32) == 4);
TEST(sizeof(msg.req_int64) == 8);
TEST(sizeof(msg.req_uint64) == 8);
TEST(sizeof(msg.req_sint64) == 8);
}
COMMENT("Test roundtrip at maximum value");
TEST_ROUNDTRIP(127, 255, 127,
32767, 65535, 32767,
INT32_MAX, UINT32_MAX, INT32_MAX,
INT64_MAX, UINT64_MAX, INT64_MAX, true);
COMMENT("Test roundtrip at minimum value");
TEST_ROUNDTRIP(-128, 0, -128,
-32768, 0, -32768,
INT32_MIN, 0, INT32_MIN,
INT64_MIN, 0, INT64_MIN, true);
COMMENT("Test overflow detection");
TEST_ROUNDTRIP(-129, 0, -128,
-32768, 0, -32768,
INT32_MIN, 0, INT32_MIN,
INT64_MIN, 0, INT64_MIN, false);
TEST_ROUNDTRIP(127, 256, 127,
32767, 65535, 32767,
INT32_MAX, UINT32_MAX, INT32_MAX,
INT64_MAX, UINT64_MAX, INT64_MAX, false);
TEST_ROUNDTRIP(-128, 0, -128,
-32768, 0, -32769,
INT32_MIN, 0, INT32_MIN,
INT64_MIN, 0, INT64_MIN, false);
if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -1,15 +0,0 @@
# Simulate io errors when encoding and decoding
Import("env")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"])
ioerr = env.Program(["io_errors.c", "alltypes.pb.c",
"$COMMON/pb_encode.o", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest("io_errors.output", [ioerr, "$BUILD/alltypes/encode_alltypes.output"])

View File

@@ -1,3 +0,0 @@
* max_size:16
* max_count:5

View File

@@ -1,140 +0,0 @@
/* Simulate IO errors after each byte in a stream.
* Verifies proper error propagation.
*/
#include <stdio.h>
#include <pb_decode.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
typedef struct
{
uint8_t *buffer;
size_t fail_after;
} faulty_stream_t;
bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
{
faulty_stream_t *state = stream->state;
while (count--)
{
if (state->fail_after == 0)
PB_RETURN_ERROR(stream, "simulated");
state->fail_after--;
*buf++ = *state->buffer++;
}
return true;
}
bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
faulty_stream_t *state = stream->state;
while (count--)
{
if (state->fail_after == 0)
PB_RETURN_ERROR(stream, "simulated");
state->fail_after--;
*state->buffer++ = *buf++;
}
return true;
}
int main()
{
uint8_t buffer[2048];
size_t msglen;
AllTypes msg = AllTypes_init_zero;
/* Get some base data to run the tests with */
SET_BINARY_MODE(stdin);
msglen = fread(buffer, 1, sizeof(buffer), stdin);
/* Test IO errors on decoding */
{
bool status;
pb_istream_t stream = {&read_callback, NULL, SIZE_MAX};
faulty_stream_t fs;
size_t i;
for (i = 0; i < msglen; i++)
{
stream.bytes_left = msglen;
stream.state = &fs;
fs.buffer = buffer;
fs.fail_after = i;
status = pb_decode(&stream, AllTypes_fields, &msg);
if (status != false)
{
fprintf(stderr, "Unexpected success in decode\n");
return 2;
}
else if (strcmp(stream.errmsg, "simulated") != 0)
{
fprintf(stderr, "Wrong error in decode: %s\n", stream.errmsg);
return 3;
}
}
stream.bytes_left = msglen;
stream.state = &fs;
fs.buffer = buffer;
fs.fail_after = msglen;
status = pb_decode(&stream, AllTypes_fields, &msg);
if (!status)
{
fprintf(stderr, "Decoding failed: %s\n", stream.errmsg);
return 4;
}
}
/* Test IO errors on encoding */
{
bool status;
pb_ostream_t stream = {&write_callback, NULL, SIZE_MAX, 0};
faulty_stream_t fs;
size_t i;
for (i = 0; i < msglen; i++)
{
stream.max_size = msglen;
stream.bytes_written = 0;
stream.state = &fs;
fs.buffer = buffer;
fs.fail_after = i;
status = pb_encode(&stream, AllTypes_fields, &msg);
if (status != false)
{
fprintf(stderr, "Unexpected success in encode\n");
return 5;
}
else if (strcmp(stream.errmsg, "simulated") != 0)
{
fprintf(stderr, "Wrong error in encode: %s\n", stream.errmsg);
return 6;
}
}
stream.max_size = msglen;
stream.bytes_written = 0;
stream.state = &fs;
fs.buffer = buffer;
fs.fail_after = msglen;
status = pb_encode(&stream, AllTypes_fields, &msg);
if (!status)
{
fprintf(stderr, "Encoding failed: %s\n", stream.errmsg);
return 7;
}
}
return 0;
}

View File

@@ -1,26 +0,0 @@
# Simulate io errors when encoding and decoding
Import("env", "malloc_env")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.Command("io_errors.c", "#io_errors/io_errors.c", c)
env.NanopbProto(["alltypes", "alltypes.options"])
ioerr = env.Program(["io_errors.c", "alltypes.pb.c",
"$COMMON/pb_encode_with_malloc.o",
"$COMMON/pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
"$COMMON/malloc_wrappers.o"])
# Run tests under valgrind if available
valgrind = env.WhereIs('valgrind')
kwargs = {}
if valgrind:
kwargs['COMMAND'] = valgrind
kwargs['ARGS'] = ["-q", "--error-exitcode=99", ioerr[0].abspath]
env.RunTest("io_errors.output", [ioerr, "$BUILD/alltypes/encode_alltypes.output"], **kwargs)

View File

@@ -1,3 +0,0 @@
# Generate all fields as pointers.
* type:FT_POINTER

View File

@@ -1,13 +0,0 @@
Import("env", "malloc_env")
env.NanopbProto("mem_release.proto")
test = malloc_env.Program(["mem_release.c",
"mem_release.pb.c",
"$COMMON/pb_encode_with_malloc.o",
"$COMMON/pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
"$COMMON/malloc_wrappers.o"])
env.RunTest(test)

View File

@@ -1,185 +0,0 @@
/* Make sure that all fields are freed in various scenarios. */
#include <pb_decode.h>
#include <pb_encode.h>
#include <malloc_wrappers.h>
#include <stdio.h>
#include <test_helpers.h>
#include "mem_release.pb.h"
#define TEST(x) if (!(x)) { \
fprintf(stderr, "Test " #x " on line %d failed.\n", __LINE__); \
return false; \
}
static char *test_str_arr[] = {"1", "2", ""};
static SubMessage test_msg_arr[] = {SubMessage_init_zero, SubMessage_init_zero};
static pb_extension_t ext1, ext2;
static void fill_TestMessage(TestMessage *msg)
{
msg->static_req_submsg.dynamic_str = "12345";
msg->static_req_submsg.dynamic_str_arr_count = 3;
msg->static_req_submsg.dynamic_str_arr = test_str_arr;
msg->static_req_submsg.dynamic_submsg_count = 2;
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->has_static_opt_submsg = true;
msg->dynamic_submsg = &msg->static_req_submsg;
msg->extensions = &ext1;
ext1.type = &dynamic_ext;
ext1.dest = &msg->static_req_submsg;
ext1.next = &ext2;
ext2.type = &static_ext;
ext2.dest = &msg->static_req_submsg;
ext2.next = NULL;
}
/* Basic fields, nested submessages, extensions */
static bool test_TestMessage()
{
uint8_t buffer[256];
size_t msgsize;
/* Construct a message with various fields filled in */
{
TestMessage msg = TestMessage_init_zero;
pb_ostream_t stream;
fill_TestMessage(&msg);
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (!pb_encode(&stream, TestMessage_fields, &msg))
{
fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
return false;
}
msgsize = stream.bytes_written;
}
/* Output encoded message for debug */
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, msgsize, stdout);
/* Decode memory using dynamic allocation */
{
TestMessage msg = TestMessage_init_zero;
pb_istream_t stream;
SubMessage ext2_dest;
msg.extensions = &ext1;
ext1.type = &dynamic_ext;
ext1.dest = NULL;
ext1.next = &ext2;
ext2.type = &static_ext;
ext2.dest = &ext2_dest;
ext2.next = NULL;
stream = pb_istream_from_buffer(buffer, msgsize);
if (!pb_decode(&stream, TestMessage_fields, &msg))
{
fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&stream));
return false;
}
/* Make sure it encodes back to same data */
{
uint8_t buffer2[256];
pb_ostream_t ostream = pb_ostream_from_buffer(buffer2, sizeof(buffer2));
TEST(pb_encode(&ostream, TestMessage_fields, &msg));
TEST(ostream.bytes_written == msgsize);
TEST(memcmp(buffer, buffer2, msgsize) == 0);
}
/* Make sure that malloc counters work */
TEST(get_alloc_count() > 0);
/* Make sure that pb_release releases everything */
pb_release(TestMessage_fields, &msg);
TEST(get_alloc_count() == 0);
/* Check that double-free is a no-op */
pb_release(TestMessage_fields, &msg);
TEST(get_alloc_count() == 0);
}
return true;
}
/* Oneofs */
static bool test_OneofMessage()
{
uint8_t buffer[256];
size_t msgsize;
{
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Encode first with TestMessage */
{
OneofMessage msg = OneofMessage_init_zero;
msg.which_msgs = OneofMessage_msg1_tag;
fill_TestMessage(&msg.msgs.msg1);
if (!pb_encode(&stream, OneofMessage_fields, &msg))
{
fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
return false;
}
}
/* Encode second with SubMessage, invoking 'merge' behaviour */
{
OneofMessage msg = OneofMessage_init_zero;
msg.which_msgs = OneofMessage_msg2_tag;
msg.first = 999;
msg.msgs.msg2.dynamic_str = "ABCD";
msg.last = 888;
if (!pb_encode(&stream, OneofMessage_fields, &msg))
{
fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
return false;
}
}
msgsize = stream.bytes_written;
}
{
OneofMessage msg = OneofMessage_init_zero;
pb_istream_t stream = pb_istream_from_buffer(buffer, msgsize);
if (!pb_decode(&stream, OneofMessage_fields, &msg))
{
fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&stream));
return false;
}
TEST(msg.first == 999);
TEST(msg.which_msgs == OneofMessage_msg2_tag);
TEST(msg.msgs.msg2.dynamic_str);
TEST(strcmp(msg.msgs.msg2.dynamic_str, "ABCD") == 0);
TEST(msg.msgs.msg2.dynamic_str_arr == NULL);
TEST(msg.msgs.msg2.dynamic_submsg == NULL);
TEST(msg.last == 888);
pb_release(OneofMessage_fields, &msg);
TEST(get_alloc_count() == 0);
pb_release(OneofMessage_fields, &msg);
TEST(get_alloc_count() == 0);
}
return true;
}
int main()
{
if (test_TestMessage() && test_OneofMessage())
return 0;
else
return 1;
}

View File

@@ -1,34 +0,0 @@
syntax = "proto2";
import "nanopb.proto";
message SubMessage
{
optional string dynamic_str = 1 [(nanopb).type = FT_POINTER];
repeated string dynamic_str_arr = 2 [(nanopb).type = FT_POINTER];
repeated SubMessage dynamic_submsg = 3 [(nanopb).type = FT_POINTER];
}
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];
extensions 100 to 200;
}
extend TestMessage
{
optional SubMessage dynamic_ext = 100 [(nanopb).type = FT_POINTER];
optional SubMessage static_ext = 101 [(nanopb).type = FT_STATIC];
}
message OneofMessage
{
required int32 first = 1;
oneof msgs
{
TestMessage msg1 = 2;
SubMessage msg2 = 3;
}
required int32 last = 4;
}

View File

@@ -3,6 +3,6 @@
Import("env") Import("env")
env.NanopbProto("missing_fields") env.NanopbProto("missing_fields")
test = env.Program(["missing_fields.c", "missing_fields.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"]) test = env.Program(["missing_fields.c", "missing_fields.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_decode.o"])
env.RunTest(test) env.RunTest(test)

View File

@@ -18,11 +18,10 @@ strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS']) strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_noerr.o", "$NANOPB/pb_decode.c") strict.Object("pb_decode_noerr.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_noerr.o", "$NANOPB/pb_encode.c") strict.Object("pb_encode_noerr.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common_noerr.o", "$NANOPB/pb_common.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_noerr.o", "pb_common_noerr.o"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_noerr.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_noerr.o", "pb_common_noerr.o"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_noerr.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -1,33 +0,0 @@
# Test the 'oneof' feature for generating C unions.
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))):
env.NanopbProto('oneof')
enc = env.Program(['encode_oneof.c',
'oneof.pb.c',
'$COMMON/pb_encode.o',
'$COMMON/pb_common.o'])
dec = env.Program(['decode_oneof.c',
'oneof.pb.c',
'$COMMON/pb_decode.o',
'$COMMON/pb_common.o'])
env.RunTest("message1.pb", enc, ARGS = ['1'])
env.RunTest("message1.txt", [dec, 'message1.pb'], ARGS = ['1'])
env.RunTest("message2.pb", enc, ARGS = ['2'])
env.RunTest("message2.txt", [dec, 'message2.pb'], ARGS = ['2'])
env.RunTest("message3.pb", enc, ARGS = ['3'])
env.RunTest("message3.txt", [dec, 'message3.pb'], ARGS = ['3'])

View File

@@ -1,72 +0,0 @@
/* Decode a message using oneof fields */
#include <stdio.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "oneof.pb.h"
#include "test_helpers.h"
#include "unittests.h"
int main(int argc, char **argv)
{
uint8_t buffer[OneOfMessage_size];
OneOfMessage msg = OneOfMessage_init_zero;
pb_istream_t stream;
size_t count;
int option;
if (argc != 2)
{
fprintf(stderr, "Usage: encode_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;
}
stream = pb_istream_from_buffer(buffer, count);
if (!pb_decode(&stream, OneOfMessage_fields, &msg))
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
{
int status = 0;
/* 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 == OneOfMessage_first_tag);
TEST(msg.values.first == 999);
}
else if (option == 2)
{
TEST(msg.which_values == OneOfMessage_second_tag);
TEST(strcmp(msg.values.second, "abcd") == 0);
}
else if (option == 3)
{
TEST(msg.which_values == OneOfMessage_third_tag);
TEST(msg.values.third.array[0] == 1);
TEST(msg.values.third.array[1] == 2);
TEST(msg.values.third.array[2] == 3);
TEST(msg.values.third.array[3] == 4);
TEST(msg.values.third.array[4] == 5);
}
return status;
}
}

View File

@@ -1,64 +0,0 @@
/* Encode a message using oneof fields */
#include <stdio.h>
#include <stdlib.h>
#include <pb_encode.h>
#include "oneof.pb.h"
#include "test_helpers.h"
int main(int argc, char **argv)
{
uint8_t buffer[OneOfMessage_size];
OneOfMessage msg = OneOfMessage_init_zero;
pb_ostream_t stream;
int option;
if (argc != 2)
{
fprintf(stderr, "Usage: encode_oneof [number]\n");
return 1;
}
option = atoi(argv[1]);
/* Prefix and suffix are used to test that the union does not disturb
* other fields in the same message. */
msg.prefix = 123;
/* We encode one of the 'values' fields based on command line argument */
if (option == 1)
{
msg.which_values = OneOfMessage_first_tag;
msg.values.first = 999;
}
else if (option == 2)
{
msg.which_values = OneOfMessage_second_tag;
strcpy(msg.values.second, "abcd");
}
else if (option == 3)
{
msg.which_values = OneOfMessage_third_tag;
msg.values.third.array_count = 5;
msg.values.third.array[0] = 1;
msg.values.third.array[1] = 2;
msg.values.third.array[2] = 3;
msg.values.third.array[3] = 4;
msg.values.third.array[4] = 5;
}
msg.suffix = 321;
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (pb_encode(&stream, OneOfMessage_fields, &msg))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0;
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}

View File

@@ -1,18 +0,0 @@
import 'nanopb.proto';
message SubMessage
{
repeated int32 array = 1 [(nanopb).max_count = 8];
}
message OneOfMessage
{
required int32 prefix = 1;
oneof values
{
int32 first = 5;
string second = 6 [(nanopb).max_size = 8];
SubMessage third = 7;
}
required int32 suffix = 99;
}

View File

@@ -29,7 +29,7 @@ def modify_c(target, source, env):
env.Command("encode_alltypes.c", "#alltypes/encode_alltypes.c", modify_c) env.Command("encode_alltypes.c", "#alltypes/encode_alltypes.c", modify_c)
# Encode and compare results to original alltypes testcase # Encode and compare results to original alltypes testcase
enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"]) enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o"])
refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX" refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX"
env.RunTest(enc) env.RunTest(enc)
env.Compare(["encode_alltypes.output", "$BUILD/alltypes/encode_alltypes.output"]) env.Compare(["encode_alltypes.output", "$BUILD/alltypes/encode_alltypes.output"])

View File

@@ -1,8 +0,0 @@
# Regression test for issue 141: wrong encoded size #define for oneof messages
Import("env")
env.NanopbProto("testproto")
env.Object('testproto.pb.c')
env.Match(['testproto.pb.h', 'testproto.expected'])

View File

@@ -1,7 +0,0 @@
define SubMessage_size \s* 88
define OneOfMessage_size \s* 113
define topMessage_size \s* 70
define MyMessage1_size \s* 46
define MyMessage2_size \s* 8
define MyMessage3_size \s* 5
define MyMessage4_size \s* 18

View File

@@ -1,50 +0,0 @@
import 'nanopb.proto';
message SubMessage
{
repeated int32 array = 1 [(nanopb).max_count = 8];
}
message OneOfMessage
{
required int32 prefix = 1;
oneof values
{
int32 first = 5;
string second = 6 [(nanopb).max_size = 8];
SubMessage third = 7;
}
required int32 suffix = 99;
}
message topMessage {
required int32 start = 1;
oneof msg {
MyMessage1 msg1 = 2;
MyMessage2 msg2 = 3;
}
required int32 end = 4;
}
message MyMessage1 {
required uint32 n1 = 1;
required uint32 n2 = 2;
required string s = 3 [(nanopb).max_size = 32];
}
message MyMessage2 {
required uint32 num = 1;
required bool b = 2;
}
message MyMessage3 {
required bool bbb = 1;
required string ss = 2 [(nanopb).max_size = 1];
}
message MyMessage4 {
required bool bbbb = 1;
required string sss = 2 [(nanopb).max_size = 2];
required uint32 num = 3;
required uint32 num2 = 4;
}

View File

@@ -11,6 +11,3 @@ if p:
env.Command('pb_encode.splint', '$NANOPB/pb_encode.c', env.Command('pb_encode.splint', '$NANOPB/pb_encode.c',
'splint -f splint/splint.rc $SOURCE 2> $TARGET') 'splint -f splint/splint.rc $SOURCE 2> $TARGET')
env.Command('pb_common.splint', '$NANOPB/pb_common.c',
'splint -f splint/splint.rc $SOURCE 2> $TARGET')

View File

@@ -2,6 +2,7 @@
+partial +partial
+matchanyintegral +matchanyintegral
+strictlib +strictlib
-isoreserved # to be fixed in 0.3
-nullassign -nullassign
-predboolint -predboolint
-predboolptr -predboolptr
@@ -27,7 +28,6 @@
-kepttrans -kepttrans
-branchstate -branchstate
-immediatetrans -immediatetrans
-mustfreefresh
# These tests give false positives, compiler typically has # These tests give false positives, compiler typically has
# better warnings for these. # better warnings for these.