Compare commits

..

27 Commits

Author SHA1 Message Date
Petteri Aimonen
b2ec9e29b3 Include platform name in also the directory name in binary pkgs 2013-12-29 20:25:36 +02:00
Petteri Aimonen
55bd3d706b Merge branch 'dev_installation_packages' of https://code.google.com/p/nanopb into dev_installation_packages 2013-12-03 20:36:29 +02:00
Petteri Aimonen
a5006cc612 Add packaging script for Mac, add platform name to packages. 2013-12-03 20:35:29 +02:00
Petteri Aimonen
a0f91bbeeb Fixes for pyinstaller 2013-12-03 20:10:48 +02:00
Petteri Aimonen
7723a30bd6 Small fix for previous 2013-12-03 19:30:39 +02:00
Petteri Aimonen
98e01b2b33 Check for supported GCC CCFLAGS when building tests. 2013-12-03 19:27:08 +02:00
Petteri Aimonen
985f1b4943 Make generator print errors to stderr.
Otherwise they won't be visible when run as a protoc plugin.
2013-12-03 18:48:10 +02:00
Petteri Aimonen
df3fd72337 Add a SCons tool for nanopb protos.
This tool script is useful both for building the tests and also for use in other applications.
2013-11-23 11:04:12 +02:00
Petteri Aimonen
5ef9d5b698 Fix protoc-gen-nanopb in linux package 2013-11-17 22:37:48 +02:00
Petteri Aimonen
4ecf27c817 Include libprotoc 2013-11-17 22:33:26 +02:00
Petteri Aimonen
ccf63de0c6 Linux archive 2013-11-17 22:25:52 +02:00
Petteri Aimonen
ece793fbc9 Also include the manifest for MSVCR90.DLL 2013-11-17 22:19:54 +02:00
Petteri Aimonen
6adf4e163c Include MSVCR90.DLL also. 2013-11-17 21:43:50 +02:00
Petteri Aimonen
420ad05e06 Include Visual C++ runtime in the Windows package. 2013-11-17 21:20:12 +02:00
Petteri Aimonen
5e82a426e6 Merge branch 'dev_installation_packages' of https://code.google.com/p/nanopb into dev_installation_packages 2013-11-17 20:57:59 +02:00
Petteri Aimonen
8209a668cd README updates 2013-11-17 20:57:50 +02:00
Petteri Aimonen
be81effcf4 Windows build fixes 2013-11-17 20:37:18 +02:00
Petteri Aimonen
f1b2ba57d3 Fix protoc plugin path 2013-11-17 20:25:18 +02:00
Petteri Aimonen
d2ba776094 Actually no, it was a portability hassle 2013-11-17 20:24:32 +02:00
Petteri Aimonen
97554a41c6 Makefile tuning 2013-11-17 20:09:30 +02:00
Petteri Aimonen
b4457a86d6 Rework the Makefiles to be compatible with binary packages. 2013-11-17 20:06:13 +02:00
Petteri Aimonen
bee09c3a38 Moving files around
Renamed READMEs to README.txt to be more friendly for Windows users.
2013-11-17 20:00:58 +02:00
Petteri Aimonen
8daadc556e Package as .zip, convert linebreaks 2013-11-17 19:09:13 +02:00
Petteri Aimonen
43cc9940ad Add build script for windows package 2013-11-17 18:09:11 +02:00
Petteri Aimonen
85be7a634e Add descriptor.proto to repository to avoid messing with protoc include path. 2013-11-17 16:42:52 +02:00
Petteri Aimonen
b5ae8eb6a5 Add script for making linux binary package 2013-11-17 15:46:41 +02:00
Petteri Aimonen
2f982d30ef Move the generator .proto files to a subdir, and get rid of precompiled versions. 2013-11-17 15:07:12 +02:00
84 changed files with 655 additions and 3610 deletions

View File

@@ -1,57 +1,3 @@
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)
NOTE: If you are using the -e option with the generator, you have
to prepend . to the argument to get the same behaviour as before.
Do not automatically add a dot with generator -e option. (issue 122)
Fix problem with .options file and extension fields. (issue 125)
Don't use SIZE_MAX macro, as it is not in C89. (issue 120)
Generate #defines for initializing message structures. (issue 79)
Add skip_message option to generator. (issue 121)
Add PB_PACKED_STRUCT support for Keil MDK-ARM toolchain (issue 119)
Give better messages about the .options file path. (issue 124)
Improved tests
nanopb-0.2.8 (2014-05-20)
Fix security issue with PB_ENABLE_MALLOC. (issue 117)
Add option to not add timestamps to .pb.h and .pb.c preambles. (issue 115)
Documentation updates
Improved tests
nanopb-0.2.7 (2014-04-07)
Fix bug with default values for extension fields (issue 111)
Fix some MISRA-C warnings (issue 91)
Implemented optional malloc() support (issue 80)
Changed pointer-type bytes field datatype
Add a "found" field to pb_extension_t (issue 112)
Add convenience function pb_get_encoded_size() (issue 16)
nanopb-0.2.6 (2014-02-15)
Fix generator error with bytes callback fields (issue 99)
Fix warnings about large integer constants (issue 102)
Add comments to where STATIC_ASSERT is used (issue 96)
Add warning about unknown field names on .options (issue 105)
Move descriptor.proto to google/protobuf subdirectory (issue 104)
Improved tests
nanopb-0.2.5 (2014-01-01)
Fix a bug with encoding negative values in int32 fields (issue 97)
Create binary packages of the generator + dependencies (issue 47)
Add support for pointer-type fields to the encoder (part of issue 80)
Fixed path in FindNanopb.cmake (issue 94)
Improved tests
nanopb-0.2.4 (2013-11-07) nanopb-0.2.4 (2013-11-07)
Remove the deprecated NANOPB_INTERNALS functions from public API. Remove the deprecated NANOPB_INTERNALS functions from public API.
Document the security model. Document the security model.

View File

@@ -28,9 +28,9 @@ compiler. This has the advantage that there is no need to reimplement the
basic parsing of .proto files. However, it does mean that you need the basic parsing of .proto files. However, it does mean that you need the
Google's protobuf library in order to run the generator. Google's protobuf library in order to run the generator.
If you have downloaded a binary package for nanopb (either Windows, Linux or If you have downloaded a binary package for nanopb (either Windows or Linux
Mac OS X version), the 'protoc' binary is included in the 'generator-bin' version), the 'protoc' binary is included in the 'generator-bin' folder. In
folder. In this case, you are ready to go. Simply run this command: this case, you are ready to go. Simply run this command:
generator-bin/protoc --nanopb_out=. myprotocol.proto generator-bin/protoc --nanopb_out=. myprotocol.proto

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

@@ -47,6 +47,7 @@ Features and limitations
**Limitations** **Limitations**
#) User must provide callbacks when decoding arrays or strings without maximum size. Malloc support could be added as a separate module.
#) Some speed has been sacrificed for code size. #) Some speed has been sacrificed for code size.
#) Encoding is focused on writing to streams. For memory buffers only it could be made more efficient. #) Encoding is focused on writing to streams. For memory buffers only it could be made more efficient.
#) The deprecated Protocol Buffers feature called "groups" is not supported. #) The deprecated Protocol Buffers feature called "groups" is not supported.
@@ -103,12 +104,11 @@ requires a few header files to be available:
#) *stdbool.h*, for definition of *bool* #) *stdbool.h*, for definition of *bool*
If these header files do not come with your compiler, you can use the If these header files do not come with your compiler, you can use the
file *extra/pb_syshdr.h* instead. It contains an example of how to provide file *compat/pb_syshdr.h* instead. It contains an example of how to provide
the dependencies. You may have to edit it a bit to suit your custom platform. the dependencies. You may have to edit it a bit to suit your custom platform.
To use the pb_syshdr.h, define *PB_SYSTEM_HEADER* as *"pb_syshdr.h"* (including the quotes). To use the pb_syshdr.h, define *PB_SYSTEM_HEADER* to be the name of your custom
Similarly, you can provide a custom include file, which should provide all the dependencies header file. It should provide all the dependencies listed above.
listed above.
Running the test cases Running the test cases
====================== ======================

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,239 +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.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,8 +24,10 @@ __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_ENABLE_MALLOC Set this to enable dynamic allocation support NANOPB_INTERNALS Set this to expose the field encoder functions
in the decoder. that are hidden since nanopb-0.1.3. Starting
with nanopb-0.2.4, this flag does nothing. Use
the newer functions that have better interface.
PB_MAX_REQUIRED_FIELDS Maximum number of required fields to check for PB_MAX_REQUIRED_FIELDS Maximum number of required fields to check for
presence. Default value is 64. Increases stack presence. Default value is 64. Increases stack
usage 1 byte per every 8 fields. Compiler usage 1 byte per every 8 fields. Compiler
@@ -75,9 +77,8 @@ max_count Allocated number of entries in arrays
(*repeated* fields). (*repeated* fields).
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_STATIC* or
*FT_STATIC* or *FT_IGNORE* to force a callback *FT_IGNORE* to force a callback field, a static
field, a dynamically allocated field, a static
field or to completely ignore the field. field or to completely ignore the field.
long_names Prefix the enum name to the enum value in long_names Prefix the enum name to the enum value in
definitions, i.e. *EnumName_EnumValue*. Enabled definitions, i.e. *EnumName_EnumValue*. Enabled
@@ -416,17 +417,6 @@ Encodes the contents of a structure as a protocol buffers message and writes it
Normally pb_encode simply walks through the fields description array and serializes each field in turn. However, submessages must be serialized twice: first to calculate their size and then to actually write them to output. This causes some constraints for callback fields, which must return the same data on every call. Normally pb_encode simply walks through the fields description array and serializes each field in turn. However, submessages must be serialized twice: first to calculate their size and then to actually write them to output. This causes some constraints for callback fields, which must return the same data on every call.
pb_encode_delimited
-------------------
Calculates the length of the message, encodes it as varint and then encodes the message. ::
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
(parameters are the same as for `pb_encode`_.)
A common way to indicate the message length in Protocol Buffers is to prefix it with a varint.
This function does this, and it is compatible with *parseDelimitedFrom* in Google's protobuf library.
.. sidebar:: Encoding fields manually .. sidebar:: Encoding fields manually
The functions with names *pb_encode_\** are used when dealing with callback fields. The typical reason for using callbacks is to have an array of unlimited size. In that case, `pb_encode`_ will call your callback function, which in turn will call *pb_encode_\** functions repeatedly to write out values. The functions with names *pb_encode_\** are used when dealing with callback fields. The typical reason for using callbacks is to have an array of unlimited size. In that case, `pb_encode`_ will call your callback function, which in turn will call *pb_encode_\** functions repeatedly to write out values.
@@ -589,10 +579,6 @@ In addition to EOF, the pb_decode implementation supports terminating a message
For optional fields, this function applies the default value and sets *has_<field>* to false if the field is not present. For optional fields, this function applies the default value and sets *has_<field>* to false if the field is not present.
If *PB_ENABLE_MALLOC* is defined, this function may allocate storage for any pointer type fields.
In this case, you have to call `pb_release`_ to release the memory after you are done with the message.
On error return `pb_decode` will release the memory itself.
pb_decode_noinit pb_decode_noinit
---------------- ----------------
Same as `pb_decode`_, except does not apply the default values to fields. :: Same as `pb_decode`_, except does not apply the default values to fields. ::
@@ -603,35 +589,6 @@ Same as `pb_decode`_, except does not apply the default values to fields. ::
The destination structure should be filled with zeros before calling this function. Doing a *memset* manually can be slightly faster than using `pb_decode`_ if you don't need any default values. The destination structure should be filled with zeros before calling this function. Doing a *memset* manually can be slightly faster than using `pb_decode`_ if you don't need any default values.
In addition to decoding a single message, this function can be used to merge two messages, so that
values from previous message will remain if the new message does not contain a field.
This function *will not* release the message even on error return. If you use *PB_ENABLE_MALLOC*,
you will need to call `pb_release`_ yourself.
pb_decode_delimited
-------------------
Same as `pb_decode`_, except that it first reads a varint with the length of the message. ::
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
(parameters are the same as for `pb_decode`_.)
A common method to indicate message size in Protocol Buffers is to prefix it with a varint.
This function is compatible with *writeDelimitedTo* in the Google's Protocol Buffers library.
pb_release
----------
Releases any dynamically allocated fields.
void pb_release(const pb_field_t fields[], void *dest_struct);
:fields: A field description array. Usually autogenerated.
:dest_struct: Pointer to structure where data will be stored.
This function is only available if *PB_ENABLE_MALLOC* is defined. It will release any
pointer type fields in the structure and set the pointers to NULL.
pb_skip_varint pb_skip_varint
-------------- --------------
Skip a varint_ encoded integer without decoding it. :: Skip a varint_ encoded integer without decoding it. ::

View File

@@ -7,8 +7,6 @@ CFLAGS += -I$(NANOPB_DIR)
all: server client all: server client
.SUFFIXES:
clean: clean:
rm -f server client fileproto.pb.c fileproto.pb.h rm -f server client fileproto.pb.c fileproto.pb.h

View File

@@ -23,13 +23,9 @@
#include "fileproto.pb.h" #include "fileproto.pb.h"
#include "common.h" #include "common.h"
/* This callback function will be called once for each filename received
* from the server. The filenames will be printed out immediately, so that
* no memory has to be allocated for them.
*/
bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
{ {
FileInfo fileinfo = {}; FileInfo fileinfo;
if (!pb_decode(stream, FileInfo_fields, &fileinfo)) if (!pb_decode(stream, FileInfo_fields, &fileinfo))
return false; return false;
@@ -39,70 +35,51 @@ bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **ar
return true; return true;
} }
/* This function sends a request to socket 'fd' to list the files in
* directory given in 'path'. The results received from server will
* be printed to stdout.
*/
bool listdir(int fd, char *path) bool listdir(int fd, char *path)
{ {
/* Construct and send the request to server */ ListFilesRequest request;
ListFilesResponse response;
pb_istream_t input = pb_istream_from_socket(fd);
pb_ostream_t output = pb_ostream_from_socket(fd);
uint8_t zero = 0;
if (path == NULL)
{ {
ListFilesRequest request = {}; request.has_path = false;
pb_ostream_t output = pb_ostream_from_socket(fd); }
uint8_t zero = 0; else
{
/* In our protocol, path is optional. If it is not given, request.has_path = true;
* the server will list the root directory. */ if (strlen(path) + 1 > sizeof(request.path))
if (path == NULL)
{ {
request.has_path = false; fprintf(stderr, "Too long path.\n");
}
else
{
request.has_path = true;
if (strlen(path) + 1 > sizeof(request.path))
{
fprintf(stderr, "Too long path.\n");
return false;
}
strcpy(request.path, path);
}
/* Encode the request. It is written to the socket immediately
* through our custom stream. */
if (!pb_encode(&output, ListFilesRequest_fields, &request))
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output));
return false; return false;
} }
/* We signal the end of request with a 0 tag. */ strcpy(request.path, path);
pb_write(&output, &zero, 1);
} }
/* Read back the response from server */ if (!pb_encode(&output, ListFilesRequest_fields, &request))
{ {
ListFilesResponse response = {}; fprintf(stderr, "Encoding failed.\n");
pb_istream_t input = pb_istream_from_socket(fd); return false;
}
/* Give a pointer to our callback function, which will handle the
* filenames as they arrive. */ /* We signal the end of request with a 0 tag. */
response.file.funcs.decode = &printfile_callback; pb_write(&output, &zero, 1);
if (!pb_decode(&input, ListFilesResponse_fields, &response)) response.file.funcs.decode = &printfile_callback;
{
fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input)); if (!pb_decode(&input, ListFilesResponse_fields, &response))
return false; {
} fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
return false;
/* If the message from server decodes properly, but directory was }
* not found on server side, we get path_error == true. */
if (response.path_error) if (response.path_error)
{ {
fprintf(stderr, "Server reported error.\n"); fprintf(stderr, "Server reported error.\n");
return false; return false;
}
} }
return true; return true;
@@ -119,7 +96,6 @@ int main(int argc, char **argv)
sockfd = socket(AF_INET, SOCK_STREAM, 0); sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* Connect to server running on localhost:1234 */
memset(&servaddr, 0, sizeof(servaddr)); memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
@@ -131,11 +107,9 @@ int main(int argc, char **argv)
return 1; return 1;
} }
/* Send the directory listing request */
if (!listdir(sockfd, path)) if (!listdir(sockfd, path))
return 2; return 2;
/* Close connection */
close(sockfd); close(sockfd);
return 0; return 0;

View File

@@ -23,16 +23,11 @@
#include "fileproto.pb.h" #include "fileproto.pb.h"
#include "common.h" #include "common.h"
/* This callback function will be called once during the encoding.
* It will write out any number of FileInfo entries, without consuming unnecessary memory.
* This is accomplished by fetching the filenames one at a time and encoding them
* immediately.
*/
bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{ {
DIR *dir = (DIR*) *arg; DIR *dir = (DIR*) *arg;
struct dirent *file; struct dirent *file;
FileInfo fileinfo = {}; FileInfo fileinfo;
while ((file = readdir(dir)) != NULL) while ((file = readdir(dir)) != NULL)
{ {
@@ -40,12 +35,9 @@ bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * cons
strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name)); strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
fileinfo.name[sizeof(fileinfo.name) - 1] = '\0'; fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
/* This encodes the header for the field, based on the constant info
* from pb_field_t. */
if (!pb_encode_tag_for_field(stream, field)) if (!pb_encode_tag_for_field(stream, field))
return false; return false;
/* This encodes the data for the field, based on our FileInfo structure. */
if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo)) if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo))
return false; return false;
} }
@@ -53,59 +45,43 @@ bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * cons
return true; return true;
} }
/* Handle one arriving client connection.
* Clients are expected to send a ListFilesRequest, terminated by a '0'.
* Server will respond with a ListFilesResponse message.
*/
void handle_connection(int connfd) void handle_connection(int connfd)
{ {
DIR *directory = NULL; ListFilesRequest request;
ListFilesResponse response;
pb_istream_t input = pb_istream_from_socket(connfd);
pb_ostream_t output = pb_ostream_from_socket(connfd);
DIR *directory;
/* Decode the message from the client and open the requested directory. */ if (!pb_decode(&input, ListFilesRequest_fields, &request))
{ {
ListFilesRequest request = {}; printf("Decode failed: %s\n", PB_GET_ERROR(&input));
pb_istream_t input = pb_istream_from_socket(connfd); return;
if (!pb_decode(&input, ListFilesRequest_fields, &request))
{
printf("Decode failed: %s\n", PB_GET_ERROR(&input));
return;
}
directory = opendir(request.path);
printf("Listing directory: %s\n", request.path);
} }
/* List the files in the directory and transmit the response to client */ directory = opendir(request.path);
printf("Listing directory: %s\n", request.path);
if (directory == NULL)
{ {
ListFilesResponse response = {}; perror("opendir");
pb_ostream_t output = pb_ostream_from_socket(connfd);
if (directory == NULL) response.has_path_error = true;
{ response.path_error = true;
perror("opendir"); response.file.funcs.encode = NULL;
}
/* Directory was not found, transmit error status */ else
response.has_path_error = true; {
response.path_error = true; response.has_path_error = false;
response.file.funcs.encode = NULL; response.file.funcs.encode = &listdir_callback;
} response.file.arg = directory;
else
{
/* Directory was found, transmit filenames */
response.has_path_error = false;
response.file.funcs.encode = &listdir_callback;
response.file.arg = directory;
}
if (!pb_encode(&output, ListFilesResponse_fields, &response))
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&output));
}
} }
if (directory != NULL) if (!pb_encode(&output, ListFilesResponse_fields, &response))
closedir(directory); {
printf("Encoding failed.\n");
}
} }
int main(int argc, char **argv) int main(int argc, char **argv)
@@ -114,8 +90,8 @@ int main(int argc, char **argv)
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
int reuse = 1; int reuse = 1;
/* Listen on localhost:1234 for TCP connections */
listenfd = socket(AF_INET, SOCK_STREAM, 0); listenfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
memset(&servaddr, 0, sizeof(servaddr)); memset(&servaddr, 0, sizeof(servaddr));
@@ -136,7 +112,6 @@ int main(int argc, char **argv)
for(;;) for(;;)
{ {
/* Wait for a client */
connfd = accept(listenfd, NULL, NULL); connfd = accept(listenfd, NULL, NULL);
if (connfd < 0) if (connfd < 0)
@@ -153,6 +128,4 @@ int main(int argc, char **argv)
close(connfd); close(connfd);
} }
return 0;
} }

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

@@ -7,8 +7,6 @@ CFLAGS += -I$(NANOPB_DIR)
all: run_tests all: run_tests
.SUFFIXES:
clean: clean:
rm -f test_conversions encode_double decode_double doubleproto.pb.c doubleproto.pb.h rm -f test_conversions encode_double decode_double doubleproto.pb.c doubleproto.pb.h

View File

@@ -10,8 +10,6 @@ all: encode decode
./encode 2 | ./decode ./encode 2 | ./decode
./encode 3 | ./decode ./encode 3 | ./decode
.SUFFIXES:
clean: clean:
rm -f encode unionproto.pb.h unionproto.pb.c rm -f encode unionproto.pb.h unionproto.pb.c

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

@@ -53,16 +53,6 @@ typedef int bool;
#endif #endif
/* stdlib.h subset */
#ifdef PB_ENABLE_MALLOC
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif
#endif
/* string.h subset */ /* string.h subset */
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>

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.0" nanopb_version = "nanopb-0.2.5-dev"
import sys import sys
@@ -15,7 +15,6 @@ except:
try: try:
import google.protobuf.text_format as text_format import google.protobuf.text_format as text_format
import google.protobuf.descriptor_pb2 as descriptor
except: except:
sys.stderr.write(''' sys.stderr.write('''
************************************************************* *************************************************************
@@ -27,7 +26,7 @@ except:
try: try:
import proto.nanopb_pb2 as nanopb_pb2 import proto.nanopb_pb2 as nanopb_pb2
import proto.plugin_pb2 as plugin_pb2 import proto.descriptor_pb2 as descriptor
except: except:
sys.stderr.write(''' sys.stderr.write('''
******************************************************************** ********************************************************************
@@ -37,6 +36,7 @@ except:
''' + '\n') ''' + '\n')
raise raise
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Generation of single fields # Generation of single fields
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -52,7 +52,7 @@ datatypes = {
FieldD.TYPE_FIXED32: ('uint32_t', 'FIXED32', 4), FieldD.TYPE_FIXED32: ('uint32_t', 'FIXED32', 4),
FieldD.TYPE_FIXED64: ('uint64_t', 'FIXED64', 8), FieldD.TYPE_FIXED64: ('uint64_t', 'FIXED64', 8),
FieldD.TYPE_FLOAT: ('float', 'FLOAT', 4), FieldD.TYPE_FLOAT: ('float', 'FLOAT', 4),
FieldD.TYPE_INT32: ('int32_t', 'INT32', 10), FieldD.TYPE_INT32: ('int32_t', 'INT32', 5),
FieldD.TYPE_INT64: ('int64_t', 'INT64', 10), FieldD.TYPE_INT64: ('int64_t', 'INT64', 10),
FieldD.TYPE_SFIXED32: ('int32_t', 'SFIXED32', 4), FieldD.TYPE_SFIXED32: ('int32_t', 'SFIXED32', 4),
FieldD.TYPE_SFIXED64: ('int64_t', 'SFIXED64', 8), FieldD.TYPE_SFIXED64: ('int64_t', 'SFIXED64', 8),
@@ -169,7 +169,6 @@ class Field:
self.max_count = None self.max_count = None
self.array_decl = "" self.array_decl = ""
self.enc_size = None self.enc_size = None
self.ctype = None
# Parse field options # Parse field options
if field_options.HasField("max_size"): if field_options.HasField("max_size"):
@@ -196,34 +195,6 @@ class Field:
else: else:
raise NotImplementedError(desc.label) raise NotImplementedError(desc.label)
# Check if the field can be implemented with static allocation
# i.e. whether the data size is known.
if desc.type == FieldD.TYPE_STRING and self.max_size is None:
can_be_static = False
if desc.type == FieldD.TYPE_BYTES and self.max_size is None:
can_be_static = False
# Decide how the field data will be allocated
if field_options.type == nanopb_pb2.FT_DEFAULT:
if can_be_static:
field_options.type = nanopb_pb2.FT_STATIC
else:
field_options.type = nanopb_pb2.FT_CALLBACK
if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static:
raise Exception("Field %s is defined as static, but max_size or "
"max_count is not given." % self.name)
if field_options.type == nanopb_pb2.FT_STATIC:
self.allocation = 'STATIC'
elif field_options.type == nanopb_pb2.FT_POINTER:
self.allocation = 'POINTER'
elif field_options.type == nanopb_pb2.FT_CALLBACK:
self.allocation = 'CALLBACK'
else:
raise NotImplementedError(field_options.type)
# 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 = datatypes[desc.type] self.ctype, self.pbtype, self.enc_size = datatypes[desc.type]
@@ -235,18 +206,19 @@ class Field:
self.enc_size = 5 # protoc rejects enum values > 32 bits self.enc_size = 5 # protoc rejects enum values > 32 bits
elif desc.type == FieldD.TYPE_STRING: elif desc.type == FieldD.TYPE_STRING:
self.pbtype = 'STRING' self.pbtype = 'STRING'
self.ctype = 'char' if self.max_size is None:
if self.allocation == 'STATIC': can_be_static = False
else:
self.ctype = 'char' self.ctype = 'char'
self.array_decl += '[%d]' % self.max_size self.array_decl += '[%d]' % self.max_size
self.enc_size = varint_max_size(self.max_size) + self.max_size self.enc_size = varint_max_size(self.max_size) + self.max_size
elif desc.type == FieldD.TYPE_BYTES: elif desc.type == FieldD.TYPE_BYTES:
self.pbtype = 'BYTES' self.pbtype = 'BYTES'
if self.allocation == 'STATIC': if self.max_size is None:
can_be_static = False
else:
self.ctype = self.struct_name + self.name + 't' self.ctype = self.struct_name + self.name + 't'
self.enc_size = varint_max_size(self.max_size) + self.max_size self.enc_size = varint_max_size(self.max_size) + self.max_size
elif self.allocation == 'POINTER':
self.ctype = 'pb_bytes_array_t'
elif desc.type == FieldD.TYPE_MESSAGE: elif desc.type == FieldD.TYPE_MESSAGE:
self.pbtype = 'MESSAGE' self.pbtype = 'MESSAGE'
self.ctype = self.submsgname = names_from_type_name(desc.type_name) self.ctype = self.submsgname = names_from_type_name(desc.type_name)
@@ -254,98 +226,71 @@ class Field:
else: else:
raise NotImplementedError(desc.type) raise NotImplementedError(desc.type)
if field_options.type == nanopb_pb2.FT_DEFAULT:
if can_be_static:
field_options.type = nanopb_pb2.FT_STATIC
else:
field_options.type = nanopb_pb2.FT_CALLBACK
if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static:
raise Exception("Field %s is defined as static, but max_size or max_count is not given." % self.name)
if field_options.type == nanopb_pb2.FT_STATIC:
self.allocation = 'STATIC'
elif field_options.type == nanopb_pb2.FT_CALLBACK:
self.allocation = 'CALLBACK'
self.ctype = 'pb_callback_t'
self.array_decl = ''
else:
raise NotImplementedError(field_options.type)
def __cmp__(self, other): def __cmp__(self, other):
return cmp(self.tag, other.tag) return cmp(self.tag, other.tag)
def __str__(self): def __str__(self):
result = '' if self.rules == 'OPTIONAL' and self.allocation == 'STATIC':
if self.allocation == 'POINTER': result = ' bool has_' + self.name + ';\n'
if self.rules == 'REPEATED': elif self.rules == 'REPEATED' and self.allocation == 'STATIC':
result += ' pb_size_t ' + self.name + '_count;\n' result = ' size_t ' + self.name + '_count;\n'
if self.pbtype == 'MESSAGE':
# Use struct definition, so recursive submessages are possible
result += ' struct _%s *%s;' % (self.ctype, self.name)
elif self.rules == 'REPEATED' and self.pbtype in ['STRING', 'BYTES']:
# String/bytes arrays need to be defined as pointers to pointers
result += ' %s **%s;' % (self.ctype, self.name)
else:
result += ' %s *%s;' % (self.ctype, self.name)
elif self.allocation == 'CALLBACK':
result += ' pb_callback_t %s;' % self.name
else: else:
if self.rules == 'OPTIONAL' and self.allocation == 'STATIC': result = ''
result += ' bool has_' + self.name + ';\n' result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl)
elif self.rules == 'REPEATED' and self.allocation == 'STATIC':
result += ' pb_size_t ' + self.name + '_count;\n'
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 = None result = None
return result return result
def get_initializer(self, null_init):
'''Return literal expression for this field's default value.'''
if self.pbtype == 'MESSAGE':
if null_init:
return '%s_init_zero' % self.ctype
else:
return '%s_init_default' % self.ctype
if self.default is None or null_init:
if self.pbtype == 'STRING':
return '""'
elif self.pbtype == 'BYTES':
return '{0, {0}}'
elif self.pbtype == 'ENUM':
return '(%s)0' % self.ctype
else:
return '0'
default = str(self.default)
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:
default = '{%d, {%s}}' % (len(data), ','.join(data))
elif self.pbtype in ['FIXED32', 'UINT32']:
default += 'u'
elif self.pbtype in ['FIXED64', 'UINT64']:
default += 'ull'
elif self.pbtype in ['SFIXED64', 'INT64']:
default += 'll'
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, default = self.ctype, self.default
default = self.get_initializer(False)
array_decl = '' array_decl = ''
if self.pbtype == 'STRING': if self.pbtype == 'STRING':
if self.allocation != 'STATIC': if self.allocation != 'STATIC':
return None # Not implemented return None # Not implemented
array_decl = '[%d]' % self.max_size array_decl = '[%d]' % self.max_size
default = str(self.default).encode('string_escape')
default = default.replace('"', '\\"')
default = '"' + default + '"'
elif self.pbtype == 'BYTES': elif self.pbtype == 'BYTES':
if self.allocation != 'STATIC': if self.allocation != 'STATIC':
return None # Not implemented return None # Not implemented
data = self.default.decode('string_escape')
data = ['0x%02x' % ord(c) for c in data]
default = '{%d, {%s}}' % (len(data), ','.join(data))
if declaration_only: if declaration_only:
return 'extern const %s %s_default%s;' % (ctype, self.struct_name + self.name, array_decl) return 'extern const %s %s_default%s;' % (ctype, self.struct_name + self.name, array_decl)
@@ -361,10 +306,10 @@ 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_FIELD(%3d, ' % self.tag result = ' PB_FIELD2(%3d, ' % self.tag
result += '%-8s, ' % self.pbtype result += '%-8s, ' % self.pbtype
result += '%s, ' % self.rules result += '%s, ' % self.rules
result += '%-8s, ' % self.allocation result += '%s, ' % self.allocation
result += '%s, ' % ("FIRST" if not prev_field_name else "OTHER") result += '%s, ' % ("FIRST" if not prev_field_name else "OTHER")
result += '%s, ' % self.struct_name result += '%s, ' % self.struct_name
result += '%s, ' % self.name result += '%s, ' % self.name
@@ -376,8 +321,6 @@ class Field:
result += '0)' result += '0)'
elif self.pbtype in ['BYTES', 'STRING'] and self.allocation != 'STATIC': elif self.pbtype in ['BYTES', 'STRING'] and self.allocation != 'STATIC':
result += '0)' # Arbitrary size default values not implemented result += '0)' # Arbitrary size default values not implemented
elif self.rules == 'OPTEXT':
result += '0)' # Default value for extensions is not implemented
else: else:
result += '&%s_default)' % (self.struct_name + self.name) result += '&%s_default)' % (self.struct_name + self.name)
@@ -467,7 +410,7 @@ class ExtensionRange(Field):
def tags(self): def tags(self):
return '' return ''
def encoded_size(self, allmsgs): def encoded_size(self, allmsgs):
# We exclude extensions from the count, because they cannot be known # We exclude extensions from the count, because they cannot be known
# until runtime. Other option would be to return None here, but this # until runtime. Other option would be to return None here, but this
@@ -578,32 +521,6 @@ class Message:
result += types + '\n' result += types + '\n'
return result return result
def get_initializer(self, null_init):
if not self.ordered_fields:
return '{0}'
parts = []
for field in self.ordered_fields:
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) + '}'
def default_decl(self, declaration_only = False): def default_decl(self, declaration_only = False):
result = "" result = ""
for field in self.fields: for field in self.fields:
@@ -690,17 +607,13 @@ def parse_file(fdesc, file_options):
for names, message in iterate_messages(fdesc, base_name): for names, message in iterate_messages(fdesc, base_name):
message_options = get_nanopb_suboptions(message, file_options, names) message_options = get_nanopb_suboptions(message, file_options, names)
if message_options.skip_message:
continue
messages.append(Message(names, message, message_options)) messages.append(Message(names, message, message_options))
for enum in message.enum_type: for enum in message.enum_type:
enum_options = get_nanopb_suboptions(enum, message_options, names + enum.name) enum_options = get_nanopb_suboptions(enum, message_options, names + enum.name)
enums.append(Enum(names, enum, enum_options)) enums.append(Enum(names, enum, enum_options))
for names, extension in iterate_extensions(fdesc, base_name): for names, extension in iterate_extensions(fdesc, base_name):
field_options = get_nanopb_suboptions(extension, file_options, names + extension.name) field_options = get_nanopb_suboptions(extension, file_options, names)
if field_options.type != nanopb_pb2.FT_IGNORE: if field_options.type != nanopb_pb2.FT_IGNORE:
extensions.append(ExtensionField(names, extension, field_options)) extensions.append(ExtensionField(names, extension, field_options))
@@ -762,14 +675,11 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio
''' '''
yield '/* Automatically generated nanopb header */\n' yield '/* Automatically generated nanopb header */\n'
if options.notimestamp: yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
yield '/* Generated by %s */\n\n' % (nanopb_version)
else:
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:
@@ -779,14 +689,9 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio
for dependency in dependencies: for dependency in dependencies:
noext = os.path.splitext(dependency)[0] noext = os.path.splitext(dependency)[0]
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'
@@ -811,15 +716,6 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio
yield msg.default_decl(True) yield msg.default_decl(True)
yield '\n' yield '\n'
yield '/* Initializer values for message structs */\n'
for msg in messages:
identifier = '%s_init_default' % msg.name
yield '#define %-40s %s\n' % (identifier, msg.get_initializer(False))
for msg in messages:
identifier = '%s_init_zero' % msg.name
yield '#define %-40s %s\n' % (identifier, msg.get_initializer(True))
yield '\n'
yield '/* Field tags (for use in manual encoding/decoding) */\n' yield '/* Field tags (for use in manual encoding/decoding) */\n'
for msg in sort_dependencies(messages): for msg in sort_dependencies(messages):
for field in msg.fields: for field in msg.fields:
@@ -852,18 +748,10 @@ def generate_source(headername, enums, messages, extensions, options):
'''Generate content for a source file.''' '''Generate content for a source file.'''
yield '/* Automatically generated nanopb constant definitions */\n' yield '/* Automatically generated nanopb constant definitions */\n'
if options.notimestamp: yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
yield '/* Generated by %s */\n\n' % (nanopb_version)
else:
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
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)
@@ -904,23 +792,6 @@ def generate_source(headername, enums, messages, extensions, options):
if worst > 255 or checks: if worst > 255 or checks:
yield '\n/* Check that field information fits in pb_field_t */\n' yield '\n/* Check that field information fits in pb_field_t */\n'
if worst > 65535 or checks:
yield '#if !defined(PB_FIELD_32BIT)\n'
if worst > 65535:
yield '#error Field descriptor for %s is too large. Define PB_FIELD_32BIT to fix this.\n' % worst_field
else:
assertion = ' && '.join(str(c) + ' < 65536' for c in checks)
msgs = '_'.join(str(n) for n in checks_msgnames)
yield '/* If you get an error here, it means that you need to define PB_FIELD_32BIT\n'
yield ' * compile-time option. You can do that in pb.h or on compiler command line.\n'
yield ' * \n'
yield ' * The reason you need to do this is that some of your messages contain tag\n'
yield ' * numbers or field sizes that are larger than what can fit in 8 or 16 bit\n'
yield ' * field descriptors.\n'
yield ' */\n'
yield 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield '#endif\n\n'
if worst < 65536: if worst < 65536:
yield '#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)\n' yield '#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)\n'
if worst > 255: if worst > 255:
@@ -928,15 +799,18 @@ def generate_source(headername, enums, messages, extensions, options):
else: else:
assertion = ' && '.join(str(c) + ' < 256' for c in checks) assertion = ' && '.join(str(c) + ' < 256' for c in checks)
msgs = '_'.join(str(n) for n in checks_msgnames) msgs = '_'.join(str(n) for n in checks_msgnames)
yield '/* If you get an error here, it means that you need to define PB_FIELD_16BIT\n' yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield ' * compile-time option. You can do that in pb.h or on compiler command line.\n'
yield ' * \n'
yield ' * The reason you need to do this is that some of your messages contain tag\n'
yield ' * numbers or field sizes that are larger than what can fit in the default\n'
yield ' * 8 bit descriptors.\n'
yield ' */\n'
yield 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield '#endif\n\n' yield '#endif\n\n'
if worst > 65535 or checks:
yield '#if !defined(PB_FIELD_32BIT)\n'
if worst > 65535:
yield '#error Field descriptor for %s is too large. Define PB_FIELD_32BIT to fix this.\n' % worst_field
else:
assertion = ' && '.join(str(c) + ' < 65536' for c in checks)
msgs = '_'.join(str(n) for n in checks_msgnames)
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield '#endif\n'
# Add check for sizeof(double) # Add check for sizeof(double)
has_double = False has_double = False
@@ -951,7 +825,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'
@@ -982,7 +856,6 @@ class Globals:
'''Ugly global variables, should find a good way to pass these.''' '''Ugly global variables, should find a good way to pass these.'''
verbose_options = False verbose_options = False
separate_options = [] separate_options = []
matched_namemasks = set()
def get_nanopb_suboptions(subdesc, options, name): def get_nanopb_suboptions(subdesc, options, name):
'''Get copy of options, and merge information from subdesc.''' '''Get copy of options, and merge information from subdesc.'''
@@ -993,7 +866,6 @@ def get_nanopb_suboptions(subdesc, options, name):
dotname = '.'.join(name.parts) dotname = '.'.join(name.parts)
for namemask, options in Globals.separate_options: for namemask, options in Globals.separate_options:
if fnmatch(dotname, namemask): if fnmatch(dotname, namemask):
Globals.matched_namemasks.add(namemask)
new_options.MergeFrom(options) new_options.MergeFrom(options)
# Handle options defined in .proto # Handle options defined in .proto
@@ -1013,8 +885,8 @@ def get_nanopb_suboptions(subdesc, options, name):
new_options.MergeFrom(ext) new_options.MergeFrom(ext)
if Globals.verbose_options: if Globals.verbose_options:
sys.stderr.write("Options for " + dotname + ": ") print "Options for " + dotname + ":"
sys.stderr.write(text_format.MessageToString(new_options) + "\n") print text_format.MessageToString(new_options)
return new_options return new_options
@@ -1033,8 +905,8 @@ optparser = OptionParser(
"Output will be written to file.pb.h and file.pb.c.") "Output will be written to file.pb.h and file.pb.c.")
optparser.add_option("-x", dest="exclude", metavar="FILE", action="append", default=[], optparser.add_option("-x", dest="exclude", metavar="FILE", action="append", default=[],
help="Exclude file from generated #include list.") help="Exclude file from generated #include list.")
optparser.add_option("-e", "--extension", dest="extension", metavar="EXTENSION", default=".pb", optparser.add_option("-e", "--extension", dest="extension", metavar="EXTENSION", default="pb",
help="Set extension to use instead of '.pb' for generated files. [default: %default]") help="Set extension to use instead of 'pb' for generated files. [default: %default]")
optparser.add_option("-f", "--options-file", dest="options_file", metavar="FILE", default="%s.options", optparser.add_option("-f", "--options-file", dest="options_file", metavar="FILE", default="%s.options",
help="Set name of a separate generator options file.") help="Set name of a separate generator options file.")
optparser.add_option("-Q", "--generated-include-format", dest="genformat", optparser.add_option("-Q", "--generated-include-format", dest="genformat",
@@ -1043,8 +915,6 @@ optparser.add_option("-Q", "--generated-include-format", dest="genformat",
optparser.add_option("-L", "--library-include-format", dest="libformat", optparser.add_option("-L", "--library-include-format", dest="libformat",
metavar="FORMAT", default='#include <%s>\n', metavar="FORMAT", default='#include <%s>\n',
help="Set format string to use for including the nanopb pb.h header. [default: %default]") help="Set format string to use for including the nanopb pb.h header. [default: %default]")
optparser.add_option("-T", "--no-timestamp", dest="notimestamp", action="store_true", default=False,
help="Don't add timestamp to .pb.h and .pb.c preambles")
optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False,
help="Don't print anything except errors.") help="Don't print anything except errors.")
optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
@@ -1074,38 +944,28 @@ def process_file(filename, fdesc, options):
fdesc = descriptor.FileDescriptorSet.FromString(data).file[0] fdesc = descriptor.FileDescriptorSet.FromString(data).file[0]
# Check if there is a separate .options file # Check if there is a separate .options file
had_abspath = False
try: try:
optfilename = options.options_file % os.path.splitext(filename)[0] optfilename = options.options_file % os.path.splitext(filename)[0]
except TypeError: except TypeError:
# No %s specified, use the filename as-is # No %s specified, use the filename as-is
optfilename = options.options_file optfilename = options.options_file
had_abspath = True
if options.verbose:
print 'Reading options from ' + optfilename
if os.path.isfile(optfilename): if os.path.isfile(optfilename):
if options.verbose:
sys.stderr.write('Reading options from ' + optfilename + '\n')
Globals.separate_options = read_options_file(open(optfilename, "rU")) Globals.separate_options = read_options_file(open(optfilename, "rU"))
else: else:
# If we are given a full filename and it does not exist, give an error.
# However, don't give error when we automatically look for .options file
# with the same name as .proto.
if options.verbose or had_abspath:
sys.stderr.write('Options file not found: ' + optfilename)
Globals.separate_options = [] Globals.separate_options = []
Globals.matched_namemasks = set()
# Parse the file # Parse the file
file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename])) file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename]))
enums, messages, extensions = parse_file(fdesc, file_options) enums, messages, extensions = parse_file(fdesc, file_options)
# Decide the file names # Decide the file names
noext = os.path.splitext(filename)[0] noext = os.path.splitext(filename)[0]
headername = noext + options.extension + '.h' headername = noext + '.' + options.extension + '.h'
sourcename = noext + options.extension + '.c' sourcename = noext + '.' + options.extension + '.c'
headerbasename = os.path.basename(headername) headerbasename = os.path.basename(headername)
# List of .proto files that should not be included in the C header file # List of .proto files that should not be included in the C header file
@@ -1119,14 +979,6 @@ def process_file(filename, fdesc, options):
sourcedata = ''.join(generate_source(headerbasename, enums, sourcedata = ''.join(generate_source(headerbasename, enums,
messages, extensions, options)) messages, extensions, options))
# Check if there were any lines in .options that did not match a member
unmatched = [n for n,o in Globals.separate_options if n not in Globals.matched_namemasks]
if unmatched and not options.quiet:
sys.stderr.write("Following patterns in " + optfilename + " did not match any fields: "
+ ', '.join(unmatched) + "\n")
if not Globals.verbose_options:
sys.stderr.write("Use protoc --nanopb-out=-v:. to see a list of the field names.\n")
return {'headername': headername, 'headerdata': headerdata, return {'headername': headername, 'headerdata': headerdata,
'sourcename': sourcename, 'sourcedata': sourcedata} 'sourcename': sourcename, 'sourcedata': sourcedata}
@@ -1148,8 +1000,7 @@ def main_cli():
results = process_file(filename, None, options) results = process_file(filename, None, options)
if not options.quiet: if not options.quiet:
sys.stderr.write("Writing to " + results['headername'] + " and " print "Writing to " + results['headername'] + " and " + results['sourcename']
+ results['sourcename'] + "\n")
open(results['headername'], 'w').write(results['headerdata']) open(results['headername'], 'w').write(results['headerdata'])
open(results['sourcename'], 'w').write(results['sourcedata']) open(results['sourcename'], 'w').write(results['sourcedata'])
@@ -1164,6 +1015,7 @@ def main_plugin():
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
import proto.plugin_pb2 as plugin_pb2
data = sys.stdin.read() data = sys.stdin.read()
request = plugin_pb2.CodeGeneratorRequest.FromString(data) request = plugin_pb2.CodeGeneratorRequest.FromString(data)
@@ -1171,7 +1023,10 @@ def main_plugin():
args = shlex.split(request.parameter) args = shlex.split(request.parameter)
options, dummy = optparser.parse_args(args) options, dummy = optparser.parse_args(args)
Globals.verbose_options = options.verbose # We can't go printing stuff to stdout
Globals.verbose_options = False
options.verbose = False
options.quiet = True
response = plugin_pb2.CodeGeneratorResponse() response = plugin_pb2.CodeGeneratorResponse()

View File

@@ -1,4 +1,4 @@
all: nanopb_pb2.py plugin_pb2.py all: nanopb_pb2.py plugin_pb2.py descriptor_pb2.py
%_pb2.py: %.proto %_pb2.py: %.proto
protoc --python_out=. $< protoc --python_out=. $<

View File

@@ -5,14 +5,13 @@
// 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.
import "google/protobuf/descriptor.proto"; import "descriptor.proto";
option java_package = "fi.kapsi.koti.jpa.nanopb"; option java_package = "fi.kapsi.koti.jpa.nanopb";
enum FieldType { enum FieldType {
FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible. FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible.
FT_CALLBACK = 1; // Always generate a callback field. FT_CALLBACK = 1; // Always generate a callback field.
FT_POINTER = 4; // Always generate a dynamically allocated field.
FT_STATIC = 2; // Generate a static field or raise an exception if not possible. FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
FT_IGNORE = 3; // Ignore the field completely. FT_IGNORE = 3; // Ignore the field completely.
} }
@@ -37,9 +36,6 @@ message NanoPBOptions {
// Note: this cannot be used on CPUs that break on unaligned // Note: this cannot be used on CPUs that break on unaligned
// accesses to variables. // accesses to variables.
optional bool packed_struct = 5 [default = false]; optional bool packed_struct = 5 [default = false];
// Skip this message
optional bool skip_message = 6 [default = false];
} }
// Extensions to protoc 'Descriptor' type in order to define options // Extensions to protoc 'Descriptor' type in order to define options

View File

@@ -46,7 +46,7 @@
package google.protobuf.compiler; package google.protobuf.compiler;
import "google/protobuf/descriptor.proto"; import "descriptor.proto";
// An encoded CodeGeneratorRequest is written to the plugin's stdin. // An encoded CodeGeneratorRequest is written to the plugin's stdin.
message CodeGeneratorRequest { message CodeGeneratorRequest {

View File

@@ -9,5 +9,4 @@
# path is already set up properly and there is no need to give # path is already set up properly and there is no need to give
# --plugin= on the command line. # --plugin= on the command line.
MYPATH=$(dirname "$0") exec python $(dirname $0)/nanopb_generator.py --protoc-plugin
exec python "$MYPATH/nanopb_generator.py" --protoc-plugin

View File

@@ -9,4 +9,4 @@
:: --plugin= on the command line. :: --plugin= on the command line.
set mydir=%~dp0 set mydir=%~dp0
python "%mydir%\nanopb_generator.py" --protoc-plugin python %mydir%\nanopb_generator.py --protoc-plugin

186
pb.h
View File

@@ -2,17 +2,14 @@
* 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 *
* uncommenting the lines, or on the compiler command line. * * uncommenting the lines, or on the compiler command line. *
*****************************************************************/ *****************************************************************/
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 1 */
/* Define this if your CPU architecture is big endian, i.e. it /* Define this if your CPU architecture is big endian, i.e. it
* stores the most-significant byte first. */ * stores the most-significant byte first. */
/* #define __BIG_ENDIAN__ 1 */ /* #define __BIG_ENDIAN__ 1 */
@@ -46,7 +43,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.0 #define NANOPB_VERSION nanopb-0.2.5-dev
/* 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:
@@ -66,10 +63,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#ifdef PB_ENABLE_MALLOC
#include <stdlib.h>
#endif
#endif #endif
/* Macro for defining packed structures (compiler dependent). /* Macro for defining packed structures (compiler dependent).
@@ -80,8 +73,8 @@
# define PB_PACKED_STRUCT_START # define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END # define PB_PACKED_STRUCT_END
# define pb_packed __attribute__((packed)) # define pb_packed __attribute__((packed))
#elif defined(__ICCARM__) || defined(__CC_ARM) #elif defined(__ICCARM__)
/* For IAR ARM and Keil MDK-ARM compilers */ /* For IAR ARM compiler */
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") # define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)")
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") # define PB_PACKED_STRUCT_END _Pragma("pack(pop)")
# define pb_packed # define pb_packed
@@ -98,27 +91,17 @@
#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 fails on your compiler for some reason, use #define STATIC_ASSERT
* #define PB_NO_STATIC_ASSERT to disable it. * to disable it. */
* #ifndef STATIC_ASSERT
* But before doing that, check carefully the error message / place where it #define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
* comes from to see if the error has a real cause. Unfortunately the error #define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
* message is not always very clear to read, but you can see the reason better #define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER
* in the place where the PB_STATIC_ASSERT macro was called.
*/
#ifndef PB_NO_STATIC_ASSERT
#ifndef PB_STATIC_ASSERT
#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(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. */
@@ -133,6 +116,11 @@
/* List of possible field types. These are used in the autogenerated code. /* List of possible field types. These are used in the autogenerated code.
* Least-significant 4 bits tell the scalar type * Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc. * Most-significant 4 bits specify repeated/required/packed etc.
*
* INT32 and UINT32 are treated the same, as are (U)INT64 and (S)FIXED*
* These types are simply casted to correct field type when they are
* assigned to the memory pointer.
* SINT* is different, though, because it is zig-zag coded.
*/ */
typedef uint8_t pb_type_t; typedef uint8_t pb_type_t;
@@ -140,33 +128,32 @@ typedef uint8_t pb_type_t;
/**** Field data types ****/ /**** Field data types ****/
/* Numeric types */ /* Numeric types */
#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ #define PB_LTYPE_VARINT 0x00 /* int32, uint32, int64, uint64, bool, enum */
#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ #define PB_LTYPE_SVARINT 0x01 /* sint32, sint64 */
#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ #define PB_LTYPE_FIXED32 0x02 /* fixed32, sfixed32, float */
#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ #define PB_LTYPE_FIXED64 0x03 /* fixed64, sfixed64, double */
#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */
/* Marker for last packable field type. */ /* Marker for last packable field type. */
#define PB_LTYPE_LAST_PACKABLE 0x04 #define PB_LTYPE_LAST_PACKABLE 0x03
/* Byte array with pre-allocated buffer. /* Byte array with pre-allocated buffer.
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */ * data_size is the length of the allocated PB_BYTES_ARRAY structure. */
#define PB_LTYPE_BYTES 0x05 #define PB_LTYPE_BYTES 0x04
/* String with pre-allocated buffer. /* String with pre-allocated buffer.
* data_size is the maximum length. */ * data_size is the maximum length. */
#define PB_LTYPE_STRING 0x06 #define PB_LTYPE_STRING 0x05
/* Submessage /* Submessage
* submsg_fields is pointer to field descriptions */ * submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMESSAGE 0x07 #define PB_LTYPE_SUBMESSAGE 0x06
/* Extension pseudo-field /* Extension pseudo-field
* The field contains a pointer to pb_extension_t */ * The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x08 #define PB_LTYPE_EXTENSION 0x07
/* Number of declared LTYPES */ /* Number of declared LTYPES */
#define PB_LTYPES_COUNT 9 #define PB_LTYPES_COUNT 8
#define PB_LTYPE_MASK 0x0F #define PB_LTYPE_MASK 0x0F
/**** Field repetition rules ****/ /**** Field repetition rules ****/
@@ -179,7 +166,6 @@ typedef uint8_t pb_type_t;
/**** Field allocation types ****/ /**** Field allocation types ****/
#define PB_ATYPE_STATIC 0x00 #define PB_ATYPE_STATIC 0x00
#define PB_ATYPE_POINTER 0x80
#define PB_ATYPE_CALLBACK 0x40 #define PB_ATYPE_CALLBACK 0x40
#define PB_ATYPE_MASK 0xC0 #define PB_ATYPE_MASK 0xC0
@@ -191,15 +177,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
@@ -213,8 +196,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. */
@@ -230,32 +213,26 @@ struct pb_field_s {
PB_PACKED_STRUCT_END PB_PACKED_STRUCT_END
/* Make sure that the standard integer types are of the expected sizes. /* Make sure that the standard integer types are of the expected sizes.
* All kinds of things may break otherwise.. atleast all fixed* types. * All kinds of things may break otherwise.. atleast all fixed* types. */
* STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE)
* If you get errors here, it probably means that your stdint.h is not STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE)
* correct for your platform. STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE)
*/ STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
/* 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]; } struct _pb_bytes_array_t {
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) size_t size;
struct pb_bytes_array_s {
pb_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
@@ -275,10 +252,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 {
@@ -311,9 +288,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.
@@ -335,7 +312,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;
@@ -348,26 +325,8 @@ struct pb_extension_s {
* If this extension does not match a field, the next handler is * If this extension does not match a field, the next handler is
* automatically called. */ * automatically called. */
pb_extension_t *next; pb_extension_t *next;
/* The decoder sets this to true if the extension was found.
* Ignored for encoding. */
bool found;
}; };
/* Memory allocation functions to use. You can define pb_realloc and
* pb_free to custom functions if you want. */
#ifdef PB_ENABLE_MALLOC
# ifndef pb_realloc
# define pb_realloc(ptr, size) realloc(ptr, size)
# endif
# ifndef pb_free
# define pb_free(ptr) free(ptr)
# 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)
@@ -411,22 +370,6 @@ struct pb_extension_s {
pb_membersize(st, m[0]), \ pb_membersize(st, m[0]), \
pb_arraysize(st, m), ptr} pb_arraysize(st, m), ptr}
/* Allocated fields carry the size of the actual data, not the pointer */
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Optional fields don't need a has_ variable, as information would be redundant */
#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Repeated fields have a _count field and a pointer to array of pointers */
#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
fd, pb_delta(st, m ## _count, m), \
pb_membersize(st, m[0]), 0, ptr}
/* Callbacks are much like required fields except with special datatype. */ /* Callbacks are much like required fields except with special datatype. */
#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ #define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \
@@ -467,8 +410,8 @@ struct pb_extension_s {
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT #define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT #define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING #define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT #define PB_LTYPE_MAP_UINT32 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT #define PB_LTYPE_MAP_UINT64 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION #define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
/* This is the actual macro used in field descriptions. /* This is the actual macro used in field descriptions.
@@ -479,15 +422,26 @@ 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)
@@ -499,11 +453,7 @@ struct pb_extension_s {
* messages if not used. * messages if not used.
*/ */
#ifdef PB_NO_ERRMSG #ifdef PB_NO_ERRMSG
#define PB_RETURN_ERROR(stream,msg) \ #define PB_RETURN_ERROR(stream,msg) return false
do {\
PB_UNUSED(stream); \
return false; \
} while(0)
#define PB_GET_ERROR(stream) "(errmsg disabled)" #define PB_GET_ERROR(stream) "(errmsg disabled)"
#else #else
#define PB_RETURN_ERROR(stream,msg) \ #define PB_RETURN_ERROR(stream,msg) \

View File

@@ -1,90 +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_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

@@ -13,28 +13,41 @@
#define checkreturn __attribute__((warn_unused_result)) #define checkreturn __attribute__((warn_unused_result))
#endif #endif
#define NANOPB_INTERNALS
#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 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_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 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_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);
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);
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);
@@ -49,7 +62,6 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream);
*/ */
static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
&pb_dec_varint, &pb_dec_varint,
&pb_dec_uvarint,
&pb_dec_svarint, &pb_dec_svarint,
&pb_dec_fixed32, &pb_dec_fixed32,
&pb_dec_fixed64, &pb_dec_fixed64,
@@ -116,7 +128,7 @@ bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
* This is an optimization for the varint decoding. */ * This is an optimization for the varint decoding. */
static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf)
{ {
if (stream->bytes_left == 0) if (!stream->bytes_left)
PB_RETURN_ERROR(stream, "end-of-stream"); PB_RETURN_ERROR(stream, "end-of-stream");
#ifndef PB_BUFFER_ONLY #ifndef PB_BUFFER_ONLY
@@ -160,7 +172,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
if (!pb_readbyte(stream, &byte)) if (!pb_readbyte(stream, &byte))
return false; return false;
if ((byte & 0x80) == 0) if (!(byte & 0x80))
{ {
/* Quick case, 1 byte value */ /* Quick case, 1 byte value */
result = byte; result = byte;
@@ -325,11 +337,71 @@ 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;
}
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;
}
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;
@@ -352,12 +424,12 @@ 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;
while (substream.bytes_left > 0 && *size < iter->pos->array_size) while (substream.bytes_left && *size < iter->pos->array_size)
{ {
void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
if (!func(&substream, iter->pos, pItem)) if (!func(&substream, iter->pos, pItem))
@@ -377,7 +449,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");
@@ -391,166 +463,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
} }
} }
#ifdef PB_ENABLE_MALLOC static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
/* Allocate storage for the field and store the pointer at iter->pData.
* array_size is the number of entries to reserve in an array.
* Zero size is not allowed, use pb_free() for releasing.
*/
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size)
{
void *ptr = *(void**)pData;
/* Check for multiplication overflows.
* This code avoids the costly division if the sizes are small enough.
* Multiplication is safe as long as only half of bits are set
* in either multiplicand.
*/
const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
if (data_size >= check_limit || array_size >= check_limit)
{
const size_t size_max = (size_t)-1;
if (size_max / array_size < data_size)
{
PB_RETURN_ERROR(stream, "size too large");
}
}
/* Allocate new or expand previous allocation */
/* Note: on failure the old pointer will remain in the structure,
* the message must be freed by caller also on error return. */
ptr = pb_realloc(ptr, array_size * data_size);
if (ptr == NULL)
PB_RETURN_ERROR(stream, "realloc failed");
*(void**)pData = ptr;
return true;
}
/* 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)
{
if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING ||
PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES)
{
*(void**)pItem = NULL;
}
else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
{
pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem);
}
}
#endif
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
{
#ifndef PB_ENABLE_MALLOC
PB_UNUSED(wire_type);
PB_UNUSED(iter);
PB_RETURN_ERROR(stream, "no malloc support");
#else
pb_type_t type;
pb_decoder_t func;
type = iter->pos->type;
func = PB_DECODERS[PB_LTYPE(type)];
switch (PB_HTYPE(type))
{
case PB_HTYPE_REQUIRED:
case PB_HTYPE_OPTIONAL:
if (PB_LTYPE(type) == PB_LTYPE_STRING ||
PB_LTYPE(type) == PB_LTYPE_BYTES)
{
return func(stream, iter->pos, iter->pData);
}
else
{
if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1))
return false;
initialize_pointer_field(*(void**)iter->pData, iter);
return func(stream, iter->pos, *(void**)iter->pData);
}
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
&& PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Packed array, multiple items come in at once. */
bool status = true;
pb_size_t *size = (pb_size_t*)iter->pSize;
size_t allocated_size = *size;
void *pItem;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
while (substream.bytes_left)
{
if ((size_t)*size + 1 > allocated_size)
{
/* Allocate more storage. This tries to guess the
* number of remaining entries. Round the division
* upwards. */
allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1;
if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size))
{
status = false;
break;
}
}
/* Decode the array entry */
pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size);
initialize_pointer_field(pItem, iter);
if (!func(&substream, iter->pos, pItem))
{
status = false;
break;
}
if (*size == PB_SIZE_MAX)
{
#ifndef PB_NO_ERRMSG
stream->errmsg = "too many array entries";
#endif
status = false;
break;
}
(*size)++;
}
pb_close_string_substream(stream, &substream);
return status;
}
else
{
/* Normal repeated field, i.e. only one item at a time. */
pb_size_t *size = (pb_size_t*)iter->pSize;
void *pItem;
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
(*size)++;
if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
return false;
pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1);
initialize_pointer_field(pItem, iter);
return func(stream, iter->pos, pItem);
}
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
#endif
}
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
{ {
pb_callback_t *pCallback = (pb_callback_t*)iter->pData; pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
@@ -597,16 +510,13 @@ 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)
{ {
switch (PB_ATYPE(iter->pos->type)) switch (PB_ATYPE(iter->pos->type))
{ {
case PB_ATYPE_STATIC: case PB_ATYPE_STATIC:
return decode_static_field(stream, wire_type, iter); return decode_static_field(stream, wire_type, iter);
case PB_ATYPE_POINTER:
return decode_pointer_field(stream, wire_type, iter);
case PB_ATYPE_CALLBACK: case PB_ATYPE_CALLBACK:
return decode_callback_field(stream, wire_type, iter); return decode_callback_field(stream, wire_type, iter);
@@ -621,17 +531,19 @@ 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;
bool dummy;
if (field->tag != tag) if (field->tag != tag)
return true; return true;
/* Fake a field iterator for the extension field. iter.start = field;
* It is not actually safe to advance this iterator, but decode_field iter.pos = field;
* will not even try to. */ iter.field_index = 0;
(void)pb_field_iter_begin(&iter, field, extension->dest); iter.required_field_index = 0;
iter.dest_struct = extension->dest;
iter.pData = extension->dest; iter.pData = extension->dest;
iter.pSize = &extension->found; iter.pSize = &dummy;
return decode_field(stream, wire_type, &iter); return decode_field(stream, wire_type, &iter);
} }
@@ -639,12 +551,12 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream,
/* 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;
while (extension != NULL && pos == stream->bytes_left) while (extension && pos == stream->bytes_left)
{ {
bool status; bool status;
if (extension->type->decode) if (extension->type->decode)
@@ -664,15 +576,15 @@ 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); pb_field_next(iter);
} while (iter->pos != start); } while (iter->field_index != start);
return false; return false;
} }
@@ -680,63 +592,50 @@ static bool checkreturn find_extension_field(pb_field_iter_t *iter)
/* Initialize message fields to default values, recursively */ /* Initialize message fields to default values, recursively */
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)
{ {
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))
return; /* Empty message type */
/* Initialize size/has fields and apply default values */
do do
{ {
pb_type_t type; pb_type_t type;
type = iter.pos->type; type = iter.pos->type;
if (iter.pos->tag == 0)
continue;
if (PB_ATYPE(type) == PB_ATYPE_STATIC) if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{ {
/* Initialize the size field for optional/repeated fields to 0. */
if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL)
{ {
/* Set has_field to false. Still initialize the optional field
* itself also. */
*(bool*)iter.pSize = false; *(bool*)iter.pSize = false;
} }
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{ {
/* Set array count to 0, no need to initialize contents. */ *(size_t*)iter.pSize = 0;
*(pb_size_t*)iter.pSize = 0; continue; /* Array is empty, no need to initialize contents */
continue;
} }
/* Initialize field contents to default value */
if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE) if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE)
{ {
/* 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 */
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 */
memset(iter.pData, 0, iter.pos->data_size); memset(iter.pData, 0, iter.pos->data_size);
} }
} }
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_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 */ continue; /* Don't overwrite callback */
} }
} while (pb_field_iter_next(&iter)); } while (pb_field_next(&iter));
} }
/********************* /*********************
@@ -745,13 +644,11 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str
bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{ {
uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0}; /* Used to check for required fields */
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)
{ {
@@ -767,7 +664,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)
@@ -820,10 +717,10 @@ 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)
req_field_count++; req_field_count++;
/* Check the whole bytes */ /* Check the whole bytes */
@@ -843,16 +740,8 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{ {
bool status;
pb_message_set_to_defaults(fields, dest_struct); pb_message_set_to_defaults(fields, dest_struct);
status = pb_decode_noinit(stream, fields, dest_struct); return pb_decode_noinit(stream, fields, dest_struct);
#ifdef PB_ENABLE_MALLOC
if (!status)
pb_release(fields, dest_struct);
#endif
return status;
} }
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
@@ -868,60 +757,6 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *
return status; return status;
} }
#ifdef PB_ENABLE_MALLOC
void pb_release(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_type_t type;
type = iter.pos->type;
if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
(PB_LTYPE(type) == PB_LTYPE_STRING ||
PB_LTYPE(type) == PB_LTYPE_BYTES))
{
/* Release entries in repeated string or bytes array */
void **pItem = *(void***)iter.pData;
pb_size_t count = *(pb_size_t*)iter.pSize;
while (count--)
{
pb_free(*pItem);
*pItem++ = NULL;
}
}
else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
{
/* Release fields in submessages */
void *pItem = *(void**)iter.pData;
pb_size_t count = (pItem ? 1 : 0);
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(pb_size_t*)iter.pSize;
}
while (count--)
{
pb_release((const pb_field_t*)iter.pos->ptr, pItem);
pItem = (uint8_t*)pItem + iter.pos->data_size;
}
}
/* Release main item */
pb_free(*(void**)iter.pData);
*(void**)iter.pData = NULL;
}
} while (pb_field_iter_next(&iter));
}
#endif
/* Field decoders */ /* Field decoders */
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest)
@@ -980,25 +815,7 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
#endif #endif
} }
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
switch (field->data_size)
{
case 1: *(int8_t*)dest = (int8_t)value; break;
case 2: *(int16_t*)dest = (int16_t)value; break;
case 4: *(int32_t*)dest = (int32_t)value; break;
case 8: *(int64_t*)dest = (int64_t)value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
return true;
}
static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint64_t value; uint64_t value;
if (!pb_decode_varint(stream, &value)) if (!pb_decode_varint(stream, &value))
@@ -1006,6 +823,8 @@ static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *f
switch (field->data_size) switch (field->data_size)
{ {
case 1: *(uint8_t*)dest = (uint8_t)value; break;
case 2: *(uint16_t*)dest = (uint16_t)value; break;
case 4: *(uint32_t*)dest = (uint32_t)value; break; case 4: *(uint32_t*)dest = (uint32_t)value; break;
case 8: *(uint64_t*)dest = value; break; case 8: *(uint64_t*)dest = value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size"); default: PB_RETURN_ERROR(stream, "invalid data_size");
@@ -1014,7 +833,7 @@ static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *f
return true; return true;
} }
static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
int64_t value; int64_t value;
if (!pb_decode_svarint(stream, &value)) if (!pb_decode_svarint(stream, &value))
@@ -1030,85 +849,51 @@ static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *f
return true; return true;
} }
static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) 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) 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);
} }
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint32_t size; pb_bytes_array_t *x = (pb_bytes_array_t*)dest;
pb_bytes_array_t *bdest;
if (!pb_decode_varint32(stream, &size)) uint32_t temp;
if (!pb_decode_varint32(stream, &temp))
return false; return false;
x->size = temp;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) /* Check length, noting the space taken by the size_t header. */
{ if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
if (!allocate_field(stream, dest, PB_BYTES_ARRAY_T_ALLOCSIZE(size), 1))
return false;
bdest = *(pb_bytes_array_t**)dest;
#endif
}
else
{
if (PB_BYTES_ARRAY_T_ALLOCSIZE(size) > field->data_size)
PB_RETURN_ERROR(stream, "bytes overflow");
bdest = (pb_bytes_array_t*)dest;
}
if (size > PB_SIZE_MAX)
{
PB_RETURN_ERROR(stream, "bytes overflow"); PB_RETURN_ERROR(stream, "bytes overflow");
}
return pb_read(stream, x->bytes, x->size);
bdest->size = (pb_size_t)size;
return pb_read(stream, bdest->bytes, size);
} }
static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint32_t size; uint32_t size;
size_t alloc_size;
bool status; bool status;
if (!pb_decode_varint32(stream, &size)) if (!pb_decode_varint32(stream, &size))
return false; return false;
/* Space for null terminator */ /* Check length, noting the null terminator */
alloc_size = size + 1; if (size + 1 > field->data_size)
PB_RETURN_ERROR(stream, "string overflow");
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
if (!allocate_field(stream, dest, alloc_size, 1))
return false;
dest = *(void**)dest;
#endif
}
else
{
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "string overflow");
}
status = pb_read(stream, (uint8_t*)dest, size); status = pb_read(stream, (uint8_t*)dest, size);
*((uint8_t*)dest + size) = 0; *((uint8_t*)dest + size) = 0;
return status; return status;
} }
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
bool status; bool status;
pb_istream_t substream; pb_istream_t substream;

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.
@@ -73,9 +73,6 @@ bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struc
* *
* This can also be used for 'merging' two messages, i.e. update only the * This can also be used for 'merging' two messages, i.e. update only the
* fields that exist in the new message. * fields that exist in the new message.
*
* Note: If this function returns with an error, it will not release any
* dynamically allocated fields. You will need to call pb_release() yourself.
*/ */
bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
@@ -85,14 +82,6 @@ bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *des
*/ */
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
#ifdef PB_ENABLE_MALLOC
/* Release any allocated pointer fields. If you use dynamic allocation, you should
* call this for any successfully decoded message when you are done with it. If
* pb_decode() returns with an error, the message is already released.
*/
void pb_release(const pb_field_t fields[], void *dest_struct);
#endif
/************************************** /**************************************
* Functions for manipulating streams * * Functions for manipulating streams *

View File

@@ -3,9 +3,9 @@
* 2011 Petteri Aimonen <jpa@kapsi.fi> * 2011 Petteri Aimonen <jpa@kapsi.fi>
*/ */
#define NANOPB_INTERNALS
#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
@@ -28,7 +28,6 @@ static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *fie
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); static bool checkreturn pb_enc_svarint(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); static bool checkreturn pb_enc_fixed32(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); static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
@@ -41,7 +40,6 @@ static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t
*/ */
static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
&pb_enc_varint, &pb_enc_varint,
&pb_enc_uvarint,
&pb_enc_svarint, &pb_enc_svarint,
&pb_enc_fixed32, &pb_enc_fixed32,
&pb_enc_fixed64, &pb_enc_fixed64,
@@ -118,8 +116,8 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
if (count == 0) if (count == 0)
return true; return true;
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) if (count > field->array_size)
PB_RETURN_ERROR(stream, "array max size exceeded"); PB_RETURN_ERROR(stream, "array max size exceeded");
/* We always pack arrays if the datatype allows it. */ /* We always pack arrays if the datatype allows it. */
@@ -172,23 +170,8 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
{ {
if (!pb_encode_tag_for_field(stream, field)) if (!pb_encode_tag_for_field(stream, field))
return false; return false;
if (!func(stream, field, p))
/* Normally the data is stored directly in the array entries, but return false;
* for pointer-type string and bytes fields, the array entries are
* actually pointers themselves also. So we have to dereference once
* more to get to the actual data. */
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
(PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES))
{
if (!func(stream, field, *(const void* const*)p))
return false;
}
else
{
if (!func(stream, field, p))
return false;
}
p = (const char*)p + field->data_size; p = (const char*)p + field->data_size;
} }
} }
@@ -196,38 +179,25 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
return true; return true;
} }
/* Encode a field with static or pointer allocation, i.e. one whose data /* Encode a field with static allocation, i.e. one whose data is stored
* is available to the encoder directly. */ * in the structure itself. */
static bool checkreturn encode_basic_field(pb_ostream_t *stream, static bool checkreturn encode_static_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData) const pb_field_t *field, const void *pData)
{ {
pb_encoder_t func; pb_encoder_t func;
const void *pSize; const void *pSize;
bool implicit_has = true; bool dummy = true;
func = PB_ENCODERS[PB_LTYPE(field->type)]; func = PB_ENCODERS[PB_LTYPE(field->type)];
if (field->size_offset) if (field->size_offset)
pSize = (const char*)pData + field->size_offset; pSize = (const char*)pData + field->size_offset;
else else
pSize = &implicit_has; pSize = &dummy;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
/* pData is a pointer to the field, which contains pointer to
* the data. If the 2nd pointer is NULL, it is interpreted as if
* the has_field was false.
*/
pData = *(const void* const*)pData;
implicit_has = (pData != NULL);
}
switch (PB_HTYPE(field->type)) switch (PB_HTYPE(field->type))
{ {
case PB_HTYPE_REQUIRED: case PB_HTYPE_REQUIRED:
if (!pData)
PB_RETURN_ERROR(stream, "missing required field");
if (!pb_encode_tag_for_field(stream, field)) if (!pb_encode_tag_for_field(stream, field))
return false; return false;
if (!func(stream, field, pData)) if (!func(stream, field, pData))
@@ -246,7 +216,7 @@ 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;
@@ -285,8 +255,7 @@ static bool checkreturn encode_field(pb_ostream_t *stream,
switch (PB_ATYPE(field->type)) switch (PB_ATYPE(field->type))
{ {
case PB_ATYPE_STATIC: case PB_ATYPE_STATIC:
case PB_ATYPE_POINTER: return encode_static_field(stream, field, pData);
return encode_basic_field(stream, field, pData);
case PB_ATYPE_CALLBACK: case PB_ATYPE_CALLBACK:
return encode_callback_field(stream, field, pData); return encode_callback_field(stream, field, pData);
@@ -311,7 +280,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)
{ {
@@ -334,38 +303,39 @@ 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;
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;
} }
@@ -375,17 +345,6 @@ bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const
return pb_encode_submessage(stream, fields, src_struct); return pb_encode_submessage(stream, fields, src_struct);
} }
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
{
pb_ostream_t stream = PB_OSTREAM_SIZING;
if (!pb_encode(&stream, fields, src_struct))
return false;
*size = stream.bytes_written;
return true;
}
/******************** /********************
* Helper functions * * Helper functions *
********************/ ********************/
@@ -412,9 +371,9 @@ bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
{ {
uint64_t zigzagged; uint64_t zigzagged;
if (value < 0) if (value < 0)
zigzagged = ~((uint64_t)value << 1); zigzagged = (uint64_t)(~(value << 1));
else else
zigzagged = (uint64_t)value << 1; zigzagged = (uint64_t)(value << 1);
return pb_encode_varint(stream, zigzagged); return pb_encode_varint(stream, zigzagged);
} }
@@ -455,7 +414,7 @@ bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
{ {
uint64_t tag = ((uint64_t)field_number << 3) | wiretype; uint64_t tag = wiretype | (field_number << 3);
return pb_encode_varint(stream, tag); return pb_encode_varint(stream, tag);
} }
@@ -465,7 +424,6 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t
switch (PB_LTYPE(field->type)) switch (PB_LTYPE(field->type))
{ {
case PB_LTYPE_VARINT: case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT: case PB_LTYPE_SVARINT:
wiretype = PB_WT_VARINT; wiretype = PB_WT_VARINT;
break; break;
@@ -507,12 +465,7 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie
bool status; bool status;
if (!pb_encode(&substream, fields, src_struct)) if (!pb_encode(&substream, fields, src_struct))
{
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
return false; return false;
}
size = substream.bytes_written; size = substream.bytes_written;
@@ -551,30 +504,14 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie
/* Field encoders */ /* Field encoders */
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
int64_t value = 0;
/* Cases 1 and 2 are for compilers that have smaller types for bool
* or enums. */
switch (field->data_size)
{
case 1: value = *(const int8_t*)src; break;
case 2: value = *(const int16_t*)src; break;
case 4: value = *(const int32_t*)src; break;
case 8: value = *(const int64_t*)src; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
return pb_encode_varint(stream, (uint64_t)value);
}
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
uint64_t value = 0; uint64_t value = 0;
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");
@@ -583,7 +520,7 @@ static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *f
return pb_encode_varint(stream, value); return pb_encode_varint(stream, value);
} }
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
int64_t value = 0; int64_t value = 0;
@@ -597,64 +534,43 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f
return pb_encode_svarint(stream, value); return pb_encode_svarint(stream, value);
} }
static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) 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) 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);
} }
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
if (src == NULL) if (bytes->size + offsetof(pb_bytes_array_t, bytes) > field->data_size)
{
/* Threat null pointer as an empty bytes field */
return pb_encode_string(stream, NULL, 0);
}
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
{
PB_RETURN_ERROR(stream, "bytes size exceeded"); PB_RETURN_ERROR(stream, "bytes size exceeded");
}
return pb_encode_string(stream, bytes->bytes, bytes->size); return pb_encode_string(stream, bytes->bytes, bytes->size);
} }
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) 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 for-loop */
size_t size = 0; size_t size = 0;
size_t max_size = field->data_size;
const char *p = (const char*)src; const char *p = (const char*)src;
while (size < field->data_size && *p != '\0')
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
max_size = (size_t)-1;
if (src == NULL)
{ {
size = 0; /* Threat null pointer as an empty string */ size++;
} p++;
else
{
/* strnlen() is not always available, so just use a loop */
while (size < max_size && *p != '\0')
{
size++;
p++;
}
} }
return pb_encode_string(stream, (const uint8_t*)src, size); return pb_encode_string(stream, (const uint8_t*)src, size);
} }
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
if (field->ptr == NULL) if (field->ptr == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor"); PB_RETURN_ERROR(stream, "invalid field descriptor");

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.
@@ -71,10 +71,6 @@ bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_
*/ */
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Encode the message to get the size of the encoded data, but do not store
* the data. */
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
/************************************** /**************************************
* Functions for manipulating streams * * Functions for manipulating streams *
**************************************/ **************************************/

View File

@@ -4,18 +4,3 @@ all:
clean: clean:
scons -c scons -c
coverage:
rm -rf build coverage
# LCOV does not like the newer gcov format
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
mkdir build/coverage
lcov --base-directory . --directory build/ --gcov-tool gcov-4.6 -c -o build/coverage/nanopb.info
# Generate HTML
genhtml -o build/coverage build/coverage/nanopb.info

View File

@@ -19,8 +19,8 @@ env = Environment(ENV = os.environ, tools = ['default', 'nanopb'])
# Allow overriding the compiler with scons CC=??? # Allow overriding the compiler with scons CC=???
if 'CC' in ARGUMENTS: env.Replace(CC = ARGUMENTS['CC']) if 'CC' in ARGUMENTS: env.Replace(CC = ARGUMENTS['CC'])
if 'CXX' in ARGUMENTS: env.Replace(CXX = ARGUMENTS['CXX']) if 'CXX' in ARGUMENTS: env.Replace(CXX = ARGUMENTS['CXX'])
if 'CCFLAGS' in ARGUMENTS: env.Append(CCFLAGS = ARGUMENTS['CCFLAGS']) if 'CFLAGS' in ARGUMENTS: env.Append(CCFLAGS = ARGUMENTS['CFLAGS'])
if 'CXXFLAGS' in ARGUMENTS: env.Append(CXXFLAGS = ARGUMENTS['CXXFLAGS']) if 'CXXFLAGS' in ARGUMENTS: env.Append(CCFLAGS = ARGUMENTS['CXXFLAGS'])
# Add the builders defined in site_init.py # Add the builders defined in site_init.py
add_nanopb_builders(env) add_nanopb_builders(env)
@@ -33,16 +33,13 @@ env.Append(PROTOCPATH = '#../generator')
# Check the compilation environment, unless we are just cleaning up. # Check the compilation environment, unless we are just cleaning up.
if not env.GetOption('clean'): if not env.GetOption('clean'):
def check_ccflags(context, flags, linkflags = ''): def check_ccflags(context, flags):
'''Check if given CCFLAGS are supported''' '''Check if given CCFLAGS are supported'''
context.Message('Checking support for CCFLAGS="%s"... ' % flags) context.Message('Checking support for CCFLAGS="%s"... ' % flags)
oldflags = context.env['CCFLAGS'] oldflags = context.env['CCFLAGS']
oldlinkflags = context.env['CCFLAGS']
context.env.Append(CCFLAGS = flags) context.env.Append(CCFLAGS = flags)
context.env.Append(LINKFLAGS = linkflags)
result = context.TryCompile("int main() {return 0;}", '.c') result = context.TryCompile("int main() {return 0;}", '.c')
context.env.Replace(CCFLAGS = oldflags) context.env.Replace(CCFLAGS = oldflags)
context.env.Replace(LINKFLAGS = oldlinkflags)
context.Result(result) context.Result(result)
return result return result
@@ -53,17 +50,15 @@ if not env.GetOption('clean'):
stdint = conf.CheckCHeader('stdint.h') stdint = conf.CheckCHeader('stdint.h')
stddef = conf.CheckCHeader('stddef.h') stddef = conf.CheckCHeader('stddef.h')
string = conf.CheckCHeader('string.h') string = conf.CheckCHeader('string.h')
stdlib = conf.CheckCHeader('stdlib.h')
if not stdbool or not stdint or not stddef or not string: if not stdbool or not stdint or not stddef or not string:
conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'}) conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'})
conf.env.Append(CPPPATH = "#../extra") conf.env.Append(CPPPATH = "#../compat")
if stdbool: conf.env.Append(CPPDEFINES = {'HAVE_STDBOOL_H': 1}) if stdbool: conf.env.Append(CPPDEFINES = {'HAVE_STDBOOL_H': 1})
if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1}) if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1})
if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1}) if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1})
if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1}) if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1})
if stdlib: conf.env.Append(CPPDEFINES = {'HAVE_STDLIB_H': 1})
# Check if we can use pkg-config to find protobuf include path # Check if we can use pkg-config to find protobuf include path
status, output = conf.TryAction('pkg-config protobuf --variable=includedir > $TARGET') status, output = conf.TryAction('pkg-config protobuf --variable=includedir > $TARGET')
if status: if status:
@@ -75,24 +70,16 @@ if not env.GetOption('clean'):
if 'gcc' in env['CC']: if 'gcc' in env['CC']:
if conf.CheckLib('mudflap'): if conf.CheckLib('mudflap'):
conf.env.Append(CCFLAGS = '-fmudflap') conf.env.Append(CCFLAGS = '-fmudflap')
conf.env.Append(LINKFLAGS = '-fmudflap') conf.env.Append(LINKFLAGS = '-lmudflap -fmudflap')
# Check if we can use extra strict warning flags (only with GCC) # Check if we can use extra strict warning flags (only with GCC)
extra = '-Wcast-qual -Wlogical-op -Wconversion' extra = '-Wcast-qual -Wlogical-op -Wconversion'
extra += ' -fstrict-aliasing -Wstrict-aliasing=1'
extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls' extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls'
extra += ' -Wstack-protector ' extra += ' -Wstack-protector '
if 'gcc' in env['CC']: if 'gcc' in env['CC']:
if conf.CheckCCFLAGS(extra): if conf.CheckCCFLAGS(extra):
conf.env.Append(CORECFLAGS = extra) conf.env.Append(CORECFLAGS = extra)
# Check if we can use undefined behaviour sanitizer (only with clang)
extra = '-fsanitize=undefined '
if 'clang' in env['CC']:
if conf.CheckCCFLAGS(extra, linkflags = extra):
conf.env.Append(CORECFLAGS = extra)
conf.env.Append(LINKFLAGS = extra)
# End the config stuff # End the config stuff
env = conf.Finish() env = conf.Finish()
@@ -101,15 +88,15 @@ if 'gcc' in env['CC']:
# GNU Compiler Collection # GNU Compiler Collection
# Debug info, warnings as errors # Debug info, warnings as errors
env.Append(CFLAGS = '-ansi -pedantic -g -Wall -Werror -fprofile-arcs -ftest-coverage -fstack-protector-all') env.Append(CFLAGS = '-ansi -pedantic -g -O0 -Wall -Werror --coverage -fstack-protector-all')
env.Append(CORECFLAGS = '-Wextra') env.Append(CORECFLAGS = '-Wextra')
env.Append(LINKFLAGS = '-g --coverage') env.Append(LINKFLAGS = '--coverage')
# We currently need uint64_t anyway, even though ANSI C90 otherwise.. # We currently need uint64_t anyway, even though ANSI C90 otherwise..
env.Append(CFLAGS = '-Wno-long-long') env.Append(CFLAGS = '-Wno-long-long')
elif 'clang' in env['CC']: elif 'clang' in env['CC']:
# CLang # CLang
env.Append(CFLAGS = '-ansi -g -Wall -Werror') env.Append(CFLAGS = '-ansi -g -O0 -Wall -Werror')
env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion') env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion')
elif 'cl' in env['CC']: elif 'cl' in env['CC']:
# Microsoft Visual C++ # Microsoft Visual C++
@@ -129,10 +116,10 @@ elif 'tcc' in env['CC']:
env.SetDefault(CORECFLAGS = '') env.SetDefault(CORECFLAGS = '')
if 'clang' in env['CXX']: if 'clang++' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') env.Append(CXXFLAGS = '-g -O0 -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'g++' in env['CXX'] or 'gcc' in env['CXX']: elif 'g++' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') env.Append(CXXFLAGS = '-g -O0 -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')
@@ -141,6 +128,6 @@ 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'
for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'): for subdir in Glob('*/SConscript'):
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,32 +4,9 @@
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
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])
# Re-encode the data using protoc, and check that the results from nanopb
# match byte-per-byte to the protoc output.
env.Decode("encode_alltypes.output.decoded",
["encode_alltypes.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("encode_alltypes.output.recoded",
["encode_alltypes.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["encode_alltypes.output", "encode_alltypes.output.recoded"])
# Do the same checks with the optional fields present.
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])
env.Decode("optionals.output.decoded",
["optionals.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("optionals.output.recoded",
["optionals.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["optionals.output", "optionals.output.recoded"])

View File

@@ -8,24 +8,6 @@ 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 { enum MyEnum {
Zero = 0; Zero = 0;
First = 1; First = 1;
@@ -57,26 +39,26 @@ message AllTypes {
required EmptyMessage req_emptymsg = 18; required EmptyMessage req_emptymsg = 18;
repeated int32 rep_int32 = 21 [packed = true]; repeated int32 rep_int32 = 21;
repeated int64 rep_int64 = 22 [packed = true]; repeated int64 rep_int64 = 22;
repeated uint32 rep_uint32 = 23 [packed = true]; repeated uint32 rep_uint32 = 23;
repeated uint64 rep_uint64 = 24 [packed = true]; repeated uint64 rep_uint64 = 24;
repeated sint32 rep_sint32 = 25 [packed = true]; repeated sint32 rep_sint32 = 25;
repeated sint64 rep_sint64 = 26 [packed = true]; repeated sint64 rep_sint64 = 26;
repeated bool rep_bool = 27 [packed = true]; repeated bool rep_bool = 27;
repeated fixed32 rep_fixed32 = 28 [packed = true]; repeated fixed32 rep_fixed32 = 28;
repeated sfixed32 rep_sfixed32= 29 [packed = true]; repeated sfixed32 rep_sfixed32= 29;
repeated float rep_float = 30 [packed = true]; repeated float rep_float = 30;
repeated fixed64 rep_fixed64 = 31 [packed = true]; repeated fixed64 rep_fixed64 = 31;
repeated sfixed64 rep_sfixed64= 32 [packed = true]; repeated sfixed64 rep_sfixed64= 32;
repeated double rep_double = 33 [packed = true]; repeated double rep_double = 33;
repeated string rep_string = 34; repeated string rep_string = 34;
repeated bytes rep_bytes = 35; repeated bytes rep_bytes = 35;
repeated SubMessage rep_submsg = 36; repeated SubMessage rep_submsg = 36;
repeated MyEnum rep_enum = 37 [packed = true]; repeated MyEnum rep_enum = 37;
repeated EmptyMessage rep_emptymsg = 38; repeated EmptyMessage rep_emptymsg = 38;
optional int32 opt_int32 = 41 [default = 4041]; optional int32 opt_int32 = 41 [default = 4041];
@@ -101,9 +83,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;
// Check that extreme integer values are handled correctly
required Limits req_limits = 98;
// Just to make sure that the size of the fields has been calculated // 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. // properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 99; required int32 end = 99;

View File

@@ -19,12 +19,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)
{ {
/* Uses _init_default to just make sure that it works. */ AllTypes alltypes;
AllTypes alltypes = AllTypes_init_default;
/* Fill with garbage to better detect initialization errors */ /* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes)); memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes)) if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false; return false;
@@ -172,17 +170,6 @@ bool check_alltypes(pb_istream_t *stream, int mode)
TEST(alltypes.has_opt_emptymsg == true); TEST(alltypes.has_opt_emptymsg == true);
} }
TEST(alltypes.req_limits.int32_min == INT32_MIN);
TEST(alltypes.req_limits.int32_max == INT32_MAX);
TEST(alltypes.req_limits.uint32_min == 0);
TEST(alltypes.req_limits.uint32_max == UINT32_MAX);
TEST(alltypes.req_limits.int64_min == INT64_MIN);
TEST(alltypes.req_limits.int64_max == INT64_MAX);
TEST(alltypes.req_limits.uint64_min == 0);
TEST(alltypes.req_limits.uint64_max == UINT64_MAX);
TEST(alltypes.req_limits.enum_min == HugeEnum_Negative);
TEST(alltypes.req_limits.enum_max == HugeEnum_Positive);
TEST(alltypes.end == 1099); TEST(alltypes.end == 1099);
return true; return true;

View File

@@ -13,7 +13,7 @@ int main(int argc, char **argv)
int mode = (argc > 1) ? atoi(argv[1]) : 0; int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Initialize the structure with constants */ /* Initialize the structure with constants */
AllTypes alltypes = AllTypes_init_zero; AllTypes alltypes = {0};
alltypes.req_int32 = -1001; alltypes.req_int32 = -1001;
alltypes.req_int64 = -1002; alltypes.req_int64 = -1002;
@@ -67,17 +67,6 @@ int main(int argc, char **argv)
alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth; alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth;
alltypes.rep_emptymsg_count = 5; alltypes.rep_emptymsg_count = 5;
alltypes.req_limits.int32_min = INT32_MIN;
alltypes.req_limits.int32_max = INT32_MAX;
alltypes.req_limits.uint32_min = 0;
alltypes.req_limits.uint32_max = UINT32_MAX;
alltypes.req_limits.int64_min = INT64_MIN;
alltypes.req_limits.int64_max = INT64_MAX;
alltypes.req_limits.uint64_min = 0;
alltypes.req_limits.uint64_max = UINT64_MAX;
alltypes.req_limits.enum_min = HugeEnum_Negative;
alltypes.req_limits.enum_max = HugeEnum_Positive;
if (mode != 0) if (mode != 0)
{ {
/* Fill in values for optional fields */ /* Fill in values for optional fields */

View File

@@ -1,23 +0,0 @@
# Test the AllTypes encoding & decoding using callbacks for all fields.
Import("env")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX"
# Encode and compare results
env.RunTest(enc)
env.RunTest("decode_alltypes.output", [refdec, "encode_alltypes_callback.output"])
env.RunTest("decode_alltypes_callback.output", [dec, "encode_alltypes_callback.output"])
# Do the same thing with the optional fields present
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.refdecout", [refdec, "optionals.output"], ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])

View File

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

View File

@@ -1,424 +0,0 @@
/* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
* Note that normally there would be no reason to use callback fields for this,
* because each encoder defined here only gives a single field.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#define TEST(x) if (!(x)) { \
printf("Test " #x " failed (in field %d).\n", field->tag); \
return false; \
}
static bool read_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
TEST((int64_t)value == (long)*arg);
return true;
}
static bool read_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int64_t value;
if (!pb_decode_svarint(stream, &value))
return false;
TEST(value == (long)*arg);
return true;
}
static bool read_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
TEST(value == *(uint32_t*)*arg);
return true;
}
static bool read_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(value == *(uint64_t*)*arg);
return true;
}
static bool read_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t buf[16] = {0};
size_t len = stream->bytes_left;
if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
return false;
TEST(strcmp((char*)buf, *arg) == 0);
return true;
}
static bool read_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
SubMessage submsg = {""};
if (!pb_decode(stream, SubMessage_fields, &submsg))
return false;
TEST(memcmp(&submsg, *arg, sizeof(submsg)));
return true;
}
static bool read_emptymsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
EmptyMessage emptymsg = {0};
return pb_decode(stream, EmptyMessage_fields, &emptymsg);
}
static bool read_repeated_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int32_t** expected = (int32_t**)arg;
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int32_t** expected = (int32_t**)arg;
int64_t value;
if (!pb_decode_svarint(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t** expected = (uint32_t**)arg;
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t** expected = (uint64_t**)arg;
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t*** expected = (uint8_t***)arg;
uint8_t buf[16] = {0};
size_t len = stream->bytes_left;
if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
return false;
TEST(strcmp((char*)*(*expected)++, (char*)buf) == 0);
return true;
}
static bool read_repeated_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
SubMessage** expected = (SubMessage**)arg;
SubMessage decoded = {""};
if (!pb_decode(stream, SubMessage_fields, &decoded))
return false;
TEST(memcmp((*expected)++, &decoded, sizeof(decoded)) == 0);
return true;
}
static bool read_limits(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
Limits decoded = {0};
if (!pb_decode(stream, Limits_fields, &decoded))
return false;
TEST(decoded.int32_min == INT32_MIN);
TEST(decoded.int32_max == INT32_MAX);
TEST(decoded.uint32_min == 0);
TEST(decoded.uint32_max == UINT32_MAX);
TEST(decoded.int64_min == INT64_MIN);
TEST(decoded.int64_max == INT64_MAX);
TEST(decoded.uint64_min == 0);
TEST(decoded.uint64_max == UINT64_MAX);
TEST(decoded.enum_min == HugeEnum_Negative);
TEST(decoded.enum_max == HugeEnum_Positive);
return true;
}
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
/* Values for use from callbacks through pointers. */
uint32_t req_fixed32 = 1008;
int32_t req_sfixed32 = -1009;
float req_float = 1010.0f;
uint64_t req_fixed64 = 1011;
int64_t req_sfixed64 = -1012;
double req_double = 1013.0;
SubMessage req_submsg = {"1016", 1016};
int32_t rep_int32[5] = {0, 0, 0, 0, -2001};
int32_t rep_int64[5] = {0, 0, 0, 0, -2002};
int32_t rep_uint32[5] = {0, 0, 0, 0, 2003};
int32_t rep_uint64[5] = {0, 0, 0, 0, 2004};
int32_t rep_sint32[5] = {0, 0, 0, 0, -2005};
int32_t rep_sint64[5] = {0, 0, 0, 0, -2006};
int32_t rep_bool[5] = {false, false, false, false, true};
uint32_t rep_fixed32[5] = {0, 0, 0, 0, 2008};
int32_t rep_sfixed32[5] = {0, 0, 0, 0, -2009};
float rep_float[5] = {0, 0, 0, 0, 2010.0f};
uint64_t rep_fixed64[5] = {0, 0, 0, 0, 2011};
int64_t rep_sfixed64[5] = {0, 0, 0, 0, -2012};
double rep_double[5] = {0, 0, 0, 0, 2013.0};
char* rep_string[5] = {"", "", "", "", "2014"};
char* rep_bytes[5] = {"", "", "", "", "2015"};
SubMessage rep_submsg[5] = {{"", 0, 0, 3},
{"", 0, 0, 3},
{"", 0, 0, 3},
{"", 0, 0, 3},
{"2016", 2016, true, 2016}};
int32_t rep_enum[5] = {0, 0, 0, 0, MyEnum_Truth};
uint32_t opt_fixed32 = 3048;
int32_t opt_sfixed32 = 3049;
float opt_float = 3050.0f;
uint64_t opt_fixed64 = 3051;
int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0f;
SubMessage opt_submsg = {"3056", 3056};
/* Bind callbacks for required fields */
AllTypes alltypes;
/* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
alltypes.req_int32.funcs.decode = &read_varint;
alltypes.req_int32.arg = (void*)-1001;
alltypes.req_int64.funcs.decode = &read_varint;
alltypes.req_int64.arg = (void*)-1002;
alltypes.req_uint32.funcs.decode = &read_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint32.funcs.decode = &read_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint64.funcs.decode = &read_varint;
alltypes.req_uint64.arg = (void*)1004;
alltypes.req_sint32.funcs.decode = &read_svarint;
alltypes.req_sint32.arg = (void*)-1005;
alltypes.req_sint64.funcs.decode = &read_svarint;
alltypes.req_sint64.arg = (void*)-1006;
alltypes.req_bool.funcs.decode = &read_varint;
alltypes.req_bool.arg = (void*)true;
alltypes.req_fixed32.funcs.decode = &read_fixed32;
alltypes.req_fixed32.arg = &req_fixed32;
alltypes.req_sfixed32.funcs.decode = &read_fixed32;
alltypes.req_sfixed32.arg = &req_sfixed32;
alltypes.req_float.funcs.decode = &read_fixed32;
alltypes.req_float.arg = &req_float;
alltypes.req_fixed64.funcs.decode = &read_fixed64;
alltypes.req_fixed64.arg = &req_fixed64;
alltypes.req_sfixed64.funcs.decode = &read_fixed64;
alltypes.req_sfixed64.arg = &req_sfixed64;
alltypes.req_double.funcs.decode = &read_fixed64;
alltypes.req_double.arg = &req_double;
alltypes.req_string.funcs.decode = &read_string;
alltypes.req_string.arg = "1014";
alltypes.req_bytes.funcs.decode = &read_string;
alltypes.req_bytes.arg = "1015";
alltypes.req_submsg.funcs.decode = &read_submsg;
alltypes.req_submsg.arg = &req_submsg;
alltypes.req_enum.funcs.decode = &read_varint;
alltypes.req_enum.arg = (void*)MyEnum_Truth;
alltypes.req_emptymsg.funcs.decode = &read_emptymsg;
/* Bind callbacks for repeated fields */
alltypes.rep_int32.funcs.decode = &read_repeated_varint;
alltypes.rep_int32.arg = rep_int32;
alltypes.rep_int64.funcs.decode = &read_repeated_varint;
alltypes.rep_int64.arg = rep_int64;
alltypes.rep_uint32.funcs.decode = &read_repeated_varint;
alltypes.rep_uint32.arg = rep_uint32;
alltypes.rep_uint64.funcs.decode = &read_repeated_varint;
alltypes.rep_uint64.arg = rep_uint64;
alltypes.rep_sint32.funcs.decode = &read_repeated_svarint;
alltypes.rep_sint32.arg = rep_sint32;
alltypes.rep_sint64.funcs.decode = &read_repeated_svarint;
alltypes.rep_sint64.arg = rep_sint64;
alltypes.rep_bool.funcs.decode = &read_repeated_varint;
alltypes.rep_bool.arg = rep_bool;
alltypes.rep_fixed32.funcs.decode = &read_repeated_fixed32;
alltypes.rep_fixed32.arg = rep_fixed32;
alltypes.rep_sfixed32.funcs.decode = &read_repeated_fixed32;
alltypes.rep_sfixed32.arg = rep_sfixed32;
alltypes.rep_float.funcs.decode = &read_repeated_fixed32;
alltypes.rep_float.arg = rep_float;
alltypes.rep_fixed64.funcs.decode = &read_repeated_fixed64;
alltypes.rep_fixed64.arg = rep_fixed64;
alltypes.rep_sfixed64.funcs.decode = &read_repeated_fixed64;
alltypes.rep_sfixed64.arg = rep_sfixed64;
alltypes.rep_double.funcs.decode = &read_repeated_fixed64;
alltypes.rep_double.arg = rep_double;
alltypes.rep_string.funcs.decode = &read_repeated_string;
alltypes.rep_string.arg = rep_string;
alltypes.rep_bytes.funcs.decode = &read_repeated_string;
alltypes.rep_bytes.arg = rep_bytes;
alltypes.rep_submsg.funcs.decode = &read_repeated_submsg;
alltypes.rep_submsg.arg = rep_submsg;
alltypes.rep_enum.funcs.decode = &read_repeated_varint;
alltypes.rep_enum.arg = rep_enum;
alltypes.rep_emptymsg.funcs.decode = &read_emptymsg;
alltypes.req_limits.funcs.decode = &read_limits;
alltypes.end.funcs.decode = &read_varint;
alltypes.end.arg = (void*)1099;
/* Bind callbacks for optional fields */
if (mode == 1)
{
alltypes.opt_int32.funcs.decode = &read_varint;
alltypes.opt_int32.arg = (void*)3041;
alltypes.opt_int64.funcs.decode = &read_varint;
alltypes.opt_int64.arg = (void*)3042;
alltypes.opt_uint32.funcs.decode = &read_varint;
alltypes.opt_uint32.arg = (void*)3043;
alltypes.opt_uint64.funcs.decode = &read_varint;
alltypes.opt_uint64.arg = (void*)3044;
alltypes.opt_sint32.funcs.decode = &read_svarint;
alltypes.opt_sint32.arg = (void*)3045;
alltypes.opt_sint64.funcs.decode = &read_svarint;
alltypes.opt_sint64.arg = (void*)3046;
alltypes.opt_bool.funcs.decode = &read_varint;
alltypes.opt_bool.arg = (void*)true;
alltypes.opt_fixed32.funcs.decode = &read_fixed32;
alltypes.opt_fixed32.arg = &opt_fixed32;
alltypes.opt_sfixed32.funcs.decode = &read_fixed32;
alltypes.opt_sfixed32.arg = &opt_sfixed32;
alltypes.opt_float.funcs.decode = &read_fixed32;
alltypes.opt_float.arg = &opt_float;
alltypes.opt_fixed64.funcs.decode = &read_fixed64;
alltypes.opt_fixed64.arg = &opt_fixed64;
alltypes.opt_sfixed64.funcs.decode = &read_fixed64;
alltypes.opt_sfixed64.arg = &opt_sfixed64;
alltypes.opt_double.funcs.decode = &read_fixed64;
alltypes.opt_double.arg = &opt_double;
alltypes.opt_string.funcs.decode = &read_string;
alltypes.opt_string.arg = "3054";
alltypes.opt_bytes.funcs.decode = &read_string;
alltypes.opt_bytes.arg = "3055";
alltypes.opt_submsg.funcs.decode = &read_submsg;
alltypes.opt_submsg.arg = &opt_submsg;
alltypes.opt_enum.funcs.decode = &read_varint;
alltypes.opt_enum.arg = (void*)MyEnum_Truth;
alltypes.opt_emptymsg.funcs.decode = &read_emptymsg;
}
return pb_decode(stream, AllTypes_fields, &alltypes);
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!check_alltypes(&stream, mode))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -1,397 +0,0 @@
/* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
* Note that normally there would be no reason to use callback fields for this,
* because each encoder defined here only gives a single field.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
static bool write_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, (long)*arg);
}
static bool write_svarint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, (long)*arg);
}
static bool write_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed32(stream, *arg);
}
static bool write_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, *arg, strlen(*arg));
}
static bool write_submsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, *arg);
}
static bool write_emptymsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
EmptyMessage emptymsg = {0};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg);
}
static bool write_repeated_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, (long)*arg);
}
static bool write_repeated_svarint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, (long)*arg);
}
static bool write_repeated_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint32_t dummy = 0;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 4) && /* Number of bytes */
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, *arg);
}
static bool write_repeated_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint64_t dummy = 0;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_repeated_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, *arg, strlen(*arg));
}
static bool write_repeated_submsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
SubMessage dummy = {""};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, *arg);
}
static bool write_limits(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
Limits limits = {0};
limits.int32_min = INT32_MIN;
limits.int32_max = INT32_MAX;
limits.uint32_min = 0;
limits.uint32_max = UINT32_MAX;
limits.int64_min = INT64_MIN;
limits.int64_max = INT64_MAX;
limits.uint64_min = 0;
limits.uint64_max = UINT64_MAX;
limits.enum_min = HugeEnum_Negative;
limits.enum_max = HugeEnum_Positive;
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, Limits_fields, &limits);
}
static bool write_repeated_emptymsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
EmptyMessage emptymsg = {0};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg);
}
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Values for use from callbacks through pointers. */
uint32_t req_fixed32 = 1008;
int32_t req_sfixed32 = -1009;
float req_float = 1010.0f;
uint64_t req_fixed64 = 1011;
int64_t req_sfixed64 = -1012;
double req_double = 1013.0;
SubMessage req_submsg = {"1016", 1016};
uint32_t rep_fixed32 = 2008;
int32_t rep_sfixed32 = -2009;
float rep_float = 2010.0f;
uint64_t rep_fixed64 = 2011;
int64_t rep_sfixed64 = -2012;
double rep_double = 2013.0;
SubMessage rep_submsg = {"2016", 2016, true, 2016};
uint32_t opt_fixed32 = 3048;
int32_t opt_sfixed32 = 3049;
float opt_float = 3050.0f;
uint64_t opt_fixed64 = 3051;
int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0f;
SubMessage opt_submsg = {"3056", 3056};
/* Bind callbacks for required fields */
AllTypes alltypes = {{{0}}};
alltypes.req_int32.funcs.encode = &write_varint;
alltypes.req_int32.arg = (void*)-1001;
alltypes.req_int64.funcs.encode = &write_varint;
alltypes.req_int64.arg = (void*)-1002;
alltypes.req_uint32.funcs.encode = &write_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint32.funcs.encode = &write_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint64.funcs.encode = &write_varint;
alltypes.req_uint64.arg = (void*)1004;
alltypes.req_sint32.funcs.encode = &write_svarint;
alltypes.req_sint32.arg = (void*)-1005;
alltypes.req_sint64.funcs.encode = &write_svarint;
alltypes.req_sint64.arg = (void*)-1006;
alltypes.req_bool.funcs.encode = &write_varint;
alltypes.req_bool.arg = (void*)true;
alltypes.req_fixed32.funcs.encode = &write_fixed32;
alltypes.req_fixed32.arg = &req_fixed32;
alltypes.req_sfixed32.funcs.encode = &write_fixed32;
alltypes.req_sfixed32.arg = &req_sfixed32;
alltypes.req_float.funcs.encode = &write_fixed32;
alltypes.req_float.arg = &req_float;
alltypes.req_fixed64.funcs.encode = &write_fixed64;
alltypes.req_fixed64.arg = &req_fixed64;
alltypes.req_sfixed64.funcs.encode = &write_fixed64;
alltypes.req_sfixed64.arg = &req_sfixed64;
alltypes.req_double.funcs.encode = &write_fixed64;
alltypes.req_double.arg = &req_double;
alltypes.req_string.funcs.encode = &write_string;
alltypes.req_string.arg = "1014";
alltypes.req_bytes.funcs.encode = &write_string;
alltypes.req_bytes.arg = "1015";
alltypes.req_submsg.funcs.encode = &write_submsg;
alltypes.req_submsg.arg = &req_submsg;
alltypes.req_enum.funcs.encode = &write_varint;
alltypes.req_enum.arg = (void*)MyEnum_Truth;
alltypes.req_emptymsg.funcs.encode = &write_emptymsg;
/* Bind callbacks for repeated fields */
alltypes.rep_int32.funcs.encode = &write_repeated_varint;
alltypes.rep_int32.arg = (void*)-2001;
alltypes.rep_int64.funcs.encode = &write_repeated_varint;
alltypes.rep_int64.arg = (void*)-2002;
alltypes.rep_uint32.funcs.encode = &write_repeated_varint;
alltypes.rep_uint32.arg = (void*)2003;
alltypes.rep_uint64.funcs.encode = &write_repeated_varint;
alltypes.rep_uint64.arg = (void*)2004;
alltypes.rep_sint32.funcs.encode = &write_repeated_svarint;
alltypes.rep_sint32.arg = (void*)-2005;
alltypes.rep_sint64.funcs.encode = &write_repeated_svarint;
alltypes.rep_sint64.arg = (void*)-2006;
alltypes.rep_bool.funcs.encode = &write_repeated_varint;
alltypes.rep_bool.arg = (void*)true;
alltypes.rep_fixed32.funcs.encode = &write_repeated_fixed32;
alltypes.rep_fixed32.arg = &rep_fixed32;
alltypes.rep_sfixed32.funcs.encode = &write_repeated_fixed32;
alltypes.rep_sfixed32.arg = &rep_sfixed32;
alltypes.rep_float.funcs.encode = &write_repeated_fixed32;
alltypes.rep_float.arg = &rep_float;
alltypes.rep_fixed64.funcs.encode = &write_repeated_fixed64;
alltypes.rep_fixed64.arg = &rep_fixed64;
alltypes.rep_sfixed64.funcs.encode = &write_repeated_fixed64;
alltypes.rep_sfixed64.arg = &rep_sfixed64;
alltypes.rep_double.funcs.encode = &write_repeated_fixed64;
alltypes.rep_double.arg = &rep_double;
alltypes.rep_string.funcs.encode = &write_repeated_string;
alltypes.rep_string.arg = "2014";
alltypes.rep_bytes.funcs.encode = &write_repeated_string;
alltypes.rep_bytes.arg = "2015";
alltypes.rep_submsg.funcs.encode = &write_repeated_submsg;
alltypes.rep_submsg.arg = &rep_submsg;
alltypes.rep_enum.funcs.encode = &write_repeated_varint;
alltypes.rep_enum.arg = (void*)MyEnum_Truth;
alltypes.rep_emptymsg.funcs.encode = &write_repeated_emptymsg;
alltypes.req_limits.funcs.encode = &write_limits;
/* Bind callbacks for optional fields */
if (mode != 0)
{
alltypes.opt_int32.funcs.encode = &write_varint;
alltypes.opt_int32.arg = (void*)3041;
alltypes.opt_int64.funcs.encode = &write_varint;
alltypes.opt_int64.arg = (void*)3042;
alltypes.opt_uint32.funcs.encode = &write_varint;
alltypes.opt_uint32.arg = (void*)3043;
alltypes.opt_uint64.funcs.encode = &write_varint;
alltypes.opt_uint64.arg = (void*)3044;
alltypes.opt_sint32.funcs.encode = &write_svarint;
alltypes.opt_sint32.arg = (void*)3045;
alltypes.opt_sint64.funcs.encode = &write_svarint;
alltypes.opt_sint64.arg = (void*)3046;
alltypes.opt_bool.funcs.encode = &write_varint;
alltypes.opt_bool.arg = (void*)true;
alltypes.opt_fixed32.funcs.encode = &write_fixed32;
alltypes.opt_fixed32.arg = &opt_fixed32;
alltypes.opt_sfixed32.funcs.encode = &write_fixed32;
alltypes.opt_sfixed32.arg = &opt_sfixed32;
alltypes.opt_float.funcs.encode = &write_fixed32;
alltypes.opt_float.arg = &opt_float;
alltypes.opt_fixed64.funcs.encode = &write_fixed64;
alltypes.opt_fixed64.arg = &opt_fixed64;
alltypes.opt_sfixed64.funcs.encode = &write_fixed64;
alltypes.opt_sfixed64.arg = &opt_sfixed64;
alltypes.opt_double.funcs.encode = &write_fixed64;
alltypes.opt_double.arg = &opt_double;
alltypes.opt_string.funcs.encode = &write_string;
alltypes.opt_string.arg = "3054";
alltypes.opt_bytes.funcs.encode = &write_string;
alltypes.opt_bytes.arg = "3055";
alltypes.opt_submsg.funcs.encode = &write_submsg;
alltypes.opt_submsg.arg = &opt_submsg;
alltypes.opt_enum.funcs.encode = &write_varint;
alltypes.opt_enum.arg = (void*)MyEnum_Truth;
alltypes.opt_emptymsg.funcs.encode = &write_emptymsg;
}
alltypes.end.funcs.encode = &write_varint;
alltypes.end.arg = (void*)1099;
{
uint8_t buffer[2048];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

View File

@@ -1,49 +0,0 @@
# Encode the AllTypes message using pointers for all fields, and verify the
# output against the normal AllTypes test case.
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")
strict.Object("pb_common_with_malloc.o", "$NANOPB/pb_common.c")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes_pointer.c", "alltypes.pb.c", "pb_encode_with_malloc.o", "pb_common_with_malloc.o"])
dec = env.Program(["decode_alltypes_pointer.c", "alltypes.pb.c", "pb_decode_with_malloc.o", "pb_common_with_malloc.o"])
# Encode and compare results to non-pointer alltypes test case
env.RunTest(enc)
env.Compare(["encode_alltypes_pointer.output", "$BUILD/alltypes/encode_alltypes.output"])
# Decode (under valgrind if available)
valgrind = env.WhereIs('valgrind')
kwargs = {}
if valgrind:
kwargs['COMMAND'] = valgrind
kwargs['ARGS'] = ["-q", dec[0].abspath]
env.RunTest("decode_alltypes.output", [dec, "encode_alltypes_pointer.output"], **kwargs)
# Do the same thing with the optional fields present
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.Compare(["optionals.output", "$BUILD/alltypes/optionals.output"])
kwargs['ARGS'] = kwargs.get('ARGS', []) + ['1']
env.RunTest("optionals.decout", [dec, "optionals.output"], **kwargs)

View File

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

View File

@@ -1,174 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#define TEST(x) if (!(x)) { \
fprintf(stderr, "Test " #x " failed.\n"); \
status = false; \
}
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
bool status = true;
AllTypes alltypes;
/* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false;
TEST(alltypes.req_int32 && *alltypes.req_int32 == -1001);
TEST(alltypes.req_int64 && *alltypes.req_int64 == -1002);
TEST(alltypes.req_uint32 && *alltypes.req_uint32 == 1003);
TEST(alltypes.req_uint64 && *alltypes.req_uint64 == 1004);
TEST(alltypes.req_sint32 && *alltypes.req_sint32 == -1005);
TEST(alltypes.req_sint64 && *alltypes.req_sint64 == -1006);
TEST(alltypes.req_bool && *alltypes.req_bool == true);
TEST(alltypes.req_fixed32 && *alltypes.req_fixed32 == 1008);
TEST(alltypes.req_sfixed32 && *alltypes.req_sfixed32 == -1009);
TEST(alltypes.req_float && *alltypes.req_float == 1010.0f);
TEST(alltypes.req_fixed64 && *alltypes.req_fixed64 == 1011);
TEST(alltypes.req_sfixed64 && *alltypes.req_sfixed64 == -1012);
TEST(alltypes.req_double && *alltypes.req_double == 1013.0f);
TEST(alltypes.req_string && strcmp(alltypes.req_string, "1014") == 0);
TEST(alltypes.req_bytes && alltypes.req_bytes->size == 4);
TEST(alltypes.req_bytes && memcmp(&alltypes.req_bytes->bytes, "1015", 4) == 0);
TEST(alltypes.req_submsg && alltypes.req_submsg->substuff1
&& strcmp(alltypes.req_submsg->substuff1, "1016") == 0);
TEST(alltypes.req_submsg && alltypes.req_submsg->substuff2
&& *alltypes.req_submsg->substuff2 == 1016);
TEST(*alltypes.req_enum == MyEnum_Truth);
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4]->size == 4 && alltypes.rep_bytes[0]->size == 0);
TEST(memcmp(&alltypes.rep_bytes[4]->bytes, "2015", 4) == 0);
TEST(alltypes.rep_submsg_count == 5);
TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0');
TEST(*alltypes.rep_submsg[4].substuff2 == 2016 && *alltypes.rep_submsg[0].substuff2 == 0);
TEST(*alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == NULL);
TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero);
TEST(alltypes.rep_emptymsg_count == 5);
if (mode == 0)
{
/* Expect that optional values are not present */
TEST(alltypes.opt_int32 == NULL);
TEST(alltypes.opt_int64 == NULL);
TEST(alltypes.opt_uint32 == NULL);
TEST(alltypes.opt_uint64 == NULL);
TEST(alltypes.opt_sint32 == NULL);
TEST(alltypes.opt_sint64 == NULL);
TEST(alltypes.opt_bool == NULL);
TEST(alltypes.opt_fixed32 == NULL);
TEST(alltypes.opt_sfixed32 == NULL);
TEST(alltypes.opt_float == NULL);
TEST(alltypes.opt_fixed64 == NULL);
TEST(alltypes.opt_sfixed64 == NULL);
TEST(alltypes.opt_double == NULL);
TEST(alltypes.opt_string == NULL);
TEST(alltypes.opt_bytes == NULL);
TEST(alltypes.opt_submsg == NULL);
TEST(alltypes.opt_enum == NULL);
}
else
{
/* Expect filled-in values */
TEST(alltypes.opt_int32 && *alltypes.opt_int32 == 3041);
TEST(alltypes.opt_int64 && *alltypes.opt_int64 == 3042);
TEST(alltypes.opt_uint32 && *alltypes.opt_uint32 == 3043);
TEST(alltypes.opt_uint64 && *alltypes.opt_uint64 == 3044);
TEST(alltypes.opt_sint32 && *alltypes.opt_sint32 == 3045);
TEST(alltypes.opt_sint64 && *alltypes.opt_sint64 == 3046);
TEST(alltypes.opt_bool && *alltypes.opt_bool == true);
TEST(alltypes.opt_fixed32 && *alltypes.opt_fixed32 == 3048);
TEST(alltypes.opt_sfixed32 && *alltypes.opt_sfixed32== 3049);
TEST(alltypes.opt_float && *alltypes.opt_float == 3050.0f);
TEST(alltypes.opt_fixed64 && *alltypes.opt_fixed64 == 3051);
TEST(alltypes.opt_sfixed64 && *alltypes.opt_sfixed64== 3052);
TEST(alltypes.opt_double && *alltypes.opt_double == 3053.0);
TEST(alltypes.opt_string && strcmp(alltypes.opt_string, "3054") == 0);
TEST(alltypes.opt_bytes && alltypes.opt_bytes->size == 4);
TEST(alltypes.opt_bytes && memcmp(&alltypes.opt_bytes->bytes, "3055", 4) == 0);
TEST(alltypes.opt_submsg && strcmp(alltypes.opt_submsg->substuff1, "3056") == 0);
TEST(alltypes.opt_submsg && *alltypes.opt_submsg->substuff2 == 3056);
TEST(alltypes.opt_enum && *alltypes.opt_enum == MyEnum_Truth);
TEST(alltypes.opt_emptymsg);
}
TEST(alltypes.req_limits->int32_min && *alltypes.req_limits->int32_min == INT32_MIN);
TEST(alltypes.req_limits->int32_max && *alltypes.req_limits->int32_max == INT32_MAX);
TEST(alltypes.req_limits->uint32_min && *alltypes.req_limits->uint32_min == 0);
TEST(alltypes.req_limits->uint32_max && *alltypes.req_limits->uint32_max == UINT32_MAX);
TEST(alltypes.req_limits->int64_min && *alltypes.req_limits->int64_min == INT64_MIN);
TEST(alltypes.req_limits->int64_max && *alltypes.req_limits->int64_max == INT64_MAX);
TEST(alltypes.req_limits->uint64_min && *alltypes.req_limits->uint64_min == 0);
TEST(alltypes.req_limits->uint64_max && *alltypes.req_limits->uint64_max == UINT64_MAX);
TEST(alltypes.req_limits->enum_min && *alltypes.req_limits->enum_min == HugeEnum_Negative);
TEST(alltypes.req_limits->enum_max && *alltypes.req_limits->enum_max == HugeEnum_Positive);
TEST(alltypes.end && *alltypes.end == 1099);
pb_release(AllTypes_fields, &alltypes);
return status;
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and verify the message */
if (!check_alltypes(&stream, mode))
{
fprintf(stderr, "Test failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
else
{
return 0;
}
}

View File

@@ -1,188 +0,0 @@
/* Attempts to test all the datatypes supported by ProtoBuf.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Values for required fields */
int32_t req_int32 = -1001;
int64_t req_int64 = -1002;
uint32_t req_uint32 = 1003;
uint64_t req_uint64 = 1004;
int32_t req_sint32 = -1005;
int64_t req_sint64 = -1006;
bool req_bool = true;
uint32_t req_fixed32 = 1008;
int32_t req_sfixed32 = -1009;
float req_float = 1010.0f;
uint64_t req_fixed64 = 1011;
int64_t req_sfixed64 = -1012;
double req_double = 1013.0;
char* req_string = "1014";
PB_BYTES_ARRAY_T(4) req_bytes = {4, {'1', '0', '1', '5'}};
static int32_t req_substuff = 1016;
SubMessage req_submsg = {"1016", &req_substuff};
MyEnum req_enum = MyEnum_Truth;
EmptyMessage req_emptymsg = {0};
int32_t end = 1099;
/* Values for repeated fields */
int32_t rep_int32[5] = {0, 0, 0, 0, -2001};
int64_t rep_int64[5] = {0, 0, 0, 0, -2002};
uint32_t rep_uint32[5] = {0, 0, 0, 0, 2003};
uint64_t rep_uint64[5] = {0, 0, 0, 0, 2004};
int32_t rep_sint32[5] = {0, 0, 0, 0, -2005};
int64_t rep_sint64[5] = {0, 0, 0, 0, -2006};
bool rep_bool[5] = {false, false, false, false, true};
uint32_t rep_fixed32[5] = {0, 0, 0, 0, 2008};
int32_t rep_sfixed32[5] = {0, 0, 0, 0, -2009};
float rep_float[5] = {0, 0, 0, 0, 2010.0f};
uint64_t rep_fixed64[5] = {0, 0, 0, 0, 2011};
int64_t rep_sfixed64[5] = {0, 0, 0, 0, -2012};
double rep_double[5] = {0, 0, 0, 0, 2013.0f};
char* rep_string[5] = {"", "", "", "", "2014"};
static PB_BYTES_ARRAY_T(4) rep_bytes_4 = {4, {'2', '0', '1', '5'}};
pb_bytes_array_t *rep_bytes[5]= {NULL, NULL, NULL, NULL, (pb_bytes_array_t*)&rep_bytes_4};
static int32_t rep_sub2zero = 0;
static int32_t rep_substuff2 = 2016;
static uint32_t rep_substuff3 = 2016;
SubMessage rep_submsg[5] = {{"", &rep_sub2zero},
{"", &rep_sub2zero},
{"", &rep_sub2zero},
{"", &rep_sub2zero},
{"2016", &rep_substuff2, &rep_substuff3}};
MyEnum rep_enum[5] = {0, 0, 0, 0, MyEnum_Truth};
EmptyMessage rep_emptymsg[5] = {{0}, {0}, {0}, {0}, {0}};
/* Values for optional fields */
int32_t opt_int32 = 3041;
int64_t opt_int64 = 3042;
uint32_t opt_uint32 = 3043;
uint64_t opt_uint64 = 3044;
int32_t opt_sint32 = 3045;
int64_t opt_sint64 = 3046;
bool opt_bool = true;
uint32_t opt_fixed32 = 3048;
int32_t opt_sfixed32 = 3049;
float opt_float = 3050.0f;
uint64_t opt_fixed64 = 3051;
int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0;
char* opt_string = "3054";
PB_BYTES_ARRAY_T(4) opt_bytes = {4, {'3', '0', '5', '5'}};
static int32_t opt_substuff = 3056;
SubMessage opt_submsg = {"3056", &opt_substuff};
MyEnum opt_enum = MyEnum_Truth;
EmptyMessage opt_emptymsg = {0};
/* Values for the Limits message. */
static int32_t int32_min = INT32_MIN;
static int32_t int32_max = INT32_MAX;
static uint32_t uint32_min = 0;
static uint32_t uint32_max = UINT32_MAX;
static int64_t int64_min = INT64_MIN;
static int64_t int64_max = INT64_MAX;
static uint64_t uint64_min = 0;
static uint64_t uint64_max = UINT64_MAX;
static HugeEnum enum_min = HugeEnum_Negative;
static HugeEnum enum_max = HugeEnum_Positive;
Limits req_limits = {&int32_min, &int32_max,
&uint32_min, &uint32_max,
&int64_min, &int64_max,
&uint64_min, &uint64_max,
&enum_min, &enum_max};
/* Initialize the message struct with pointers to the fields. */
AllTypes alltypes = {0};
alltypes.req_int32 = &req_int32;
alltypes.req_int64 = &req_int64;
alltypes.req_uint32 = &req_uint32;
alltypes.req_uint64 = &req_uint64;
alltypes.req_sint32 = &req_sint32;
alltypes.req_sint64 = &req_sint64;
alltypes.req_bool = &req_bool;
alltypes.req_fixed32 = &req_fixed32;
alltypes.req_sfixed32 = &req_sfixed32;
alltypes.req_float = &req_float;
alltypes.req_fixed64 = &req_fixed64;
alltypes.req_sfixed64 = &req_sfixed64;
alltypes.req_double = &req_double;
alltypes.req_string = req_string;
alltypes.req_bytes = (pb_bytes_array_t*)&req_bytes;
alltypes.req_submsg = &req_submsg;
alltypes.req_enum = &req_enum;
alltypes.req_emptymsg = &req_emptymsg;
alltypes.req_limits = &req_limits;
alltypes.rep_int32_count = 5; alltypes.rep_int32 = rep_int32;
alltypes.rep_int64_count = 5; alltypes.rep_int64 = rep_int64;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32 = rep_uint32;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64 = rep_uint64;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32 = rep_sint32;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64 = rep_sint64;
alltypes.rep_bool_count = 5; alltypes.rep_bool = rep_bool;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32 = rep_fixed32;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32 = rep_sfixed32;
alltypes.rep_float_count = 5; alltypes.rep_float = rep_float;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64 = rep_fixed64;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64 = rep_sfixed64;
alltypes.rep_double_count = 5; alltypes.rep_double = rep_double;
alltypes.rep_string_count = 5; alltypes.rep_string = rep_string;
alltypes.rep_bytes_count = 5; alltypes.rep_bytes = rep_bytes;
alltypes.rep_submsg_count = 5; alltypes.rep_submsg = rep_submsg;
alltypes.rep_enum_count = 5; alltypes.rep_enum = rep_enum;
alltypes.rep_emptymsg_count = 5; alltypes.rep_emptymsg = rep_emptymsg;
if (mode != 0)
{
/* Fill in values for optional fields */
alltypes.opt_int32 = &opt_int32;
alltypes.opt_int64 = &opt_int64;
alltypes.opt_uint32 = &opt_uint32;
alltypes.opt_uint64 = &opt_uint64;
alltypes.opt_sint32 = &opt_sint32;
alltypes.opt_sint64 = &opt_sint64;
alltypes.opt_bool = &opt_bool;
alltypes.opt_fixed32 = &opt_fixed32;
alltypes.opt_sfixed32 = &opt_sfixed32;
alltypes.opt_float = &opt_float;
alltypes.opt_fixed64 = &opt_fixed64;
alltypes.opt_sfixed64 = &opt_sfixed64;
alltypes.opt_double = &opt_double;
alltypes.opt_string = opt_string;
alltypes.opt_bytes = (pb_bytes_array_t*)&opt_bytes;
alltypes.opt_submsg = &opt_submsg;
alltypes.opt_enum = &opt_enum;
alltypes.opt_emptymsg = &opt_emptymsg;
}
alltypes.end = &end;
{
uint8_t buffer[4096];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

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

@@ -11,7 +11,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <pb_decode.h> #include <pb_decode.h>
#include "alltypes_legacy.h" #include "alltypes_legacy.h"
#include "test_helpers.h"
#define TEST(x) if (!(x)) { \ #define TEST(x) if (!(x)) { \
printf("Test " #x " failed.\n"); \ printf("Test " #x " failed.\n"); \
@@ -177,19 +176,15 @@ bool check_alltypes(pb_istream_t *stream, int mode)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */ /* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0; int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */ /* Read the data into buffer */
SET_BINARY_MODE(stdin); uint8_t buffer[1024];
count = fread(buffer, 1, sizeof(buffer), stdin); size_t count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */ /* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count); pb_istream_t stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */ /* Decode and print out the stuff */
if (!check_alltypes(&stream, mode)) if (!check_alltypes(&stream, mode))

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

@@ -16,7 +16,7 @@
bool print_person(pb_istream_t *stream) bool print_person(pb_istream_t *stream)
{ {
int i; int i;
Person person = Person_init_zero; Person person;
if (!pb_decode(stream, Person_fields, &person)) if (!pb_decode(stream, Person_fields, &person))
return false; return false;

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

@@ -12,7 +12,7 @@
bool print_person(pb_istream_t *stream) bool print_person(pb_istream_t *stream)
{ {
int i; int i;
Person person = Person_init_zero; Person person;
if (!pb_decode(stream, Person_fields, &person)) if (!pb_decode(stream, Person_fields, &person))
return false; return false;

View File

@@ -4,6 +4,8 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.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.c", "$BUILD/alltypes/alltypes.pb.c", c) env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
@@ -13,16 +15,9 @@ env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_BUFFER_ONLY': 1}) opts.Append(CPPDEFINES = {'PB_BUFFER_ONLY': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_bufonly.o", "$NANOPB/pb_decode.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.c"])
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.c"])
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

@@ -14,4 +14,4 @@ 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")

View File

@@ -3,23 +3,18 @@
Import("env") Import("env")
# This is needed to get INT32_MIN etc. macros defined
env = env.Clone()
env.Append(CPPDEFINES = ['__STDC_LIMIT_MACROS'])
# Copy the files to .cxx extension in order to force C++ build. # Copy the files to .cxx extension in order to force C++ build.
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,6 +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. */
#define PB_ENABLE_MALLOC
#include "pb_common.c"
#include "pb_decode.c" #include "pb_decode.c"
#include <stdio.h> #include <stdio.h>
@@ -170,7 +168,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")
@@ -251,7 +249,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;
@@ -301,28 +299,6 @@ int main()
dest.submsg.data_count == 5) dest.submsg.data_count == 5)
} }
{
pb_istream_t s = {0};
void *data = NULL;
COMMENT("Testing allocate_field")
TEST(allocate_field(&s, &data, 10, 10) && data != NULL);
TEST(allocate_field(&s, &data, 10, 20) && data != NULL);
{
void *oldvalue = data;
size_t very_big = (size_t)-1;
size_t somewhat_big = very_big / 2 + 1;
size_t not_so_big = (size_t)1 << (4 * sizeof(size_t));
TEST(!allocate_field(&s, &data, very_big, 2) && data == oldvalue);
TEST(!allocate_field(&s, &data, somewhat_big, 2) && data == oldvalue);
TEST(!allocate_field(&s, &data, not_so_big, not_so_big) && data == oldvalue);
}
pb_free(data);
}
if (status != 0) if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n"); fprintf(stdout, "\n\nSome tests FAILED!\n");

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"))
@@ -282,15 +281,6 @@ int main()
TEST(WRITES(pb_encode_delimited(&s, IntegerContainer_fields, &msg), TEST(WRITES(pb_encode_delimited(&s, IntegerContainer_fields, &msg),
"\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05")) "\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
} }
{
IntegerContainer msg = {{5, {1,2,3,4,5}}};
size_t size;
COMMENT("Test pb_get_encoded_size.")
TEST(pb_get_encoded_size(&size, IntegerContainer_fields, &msg) &&
size == 9);
}
{ {
uint8_t buffer[10]; uint8_t buffer[10];

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

@@ -49,9 +49,7 @@ int main(int argc, char **argv)
} }
/* Check that the extensions decoded properly */ /* Check that the extensions decoded properly */
TEST(ext1.found)
TEST(extensionfield1 == 12345) TEST(extensionfield1 == 12345)
TEST(ext2.found)
TEST(strcmp(extensionfield2.test1, "test") == 0) TEST(strcmp(extensionfield2.test1, "test") == 0)
TEST(extensionfield2.test2 == 54321) TEST(extensionfield2.test2 == 54321)

View File

@@ -1,7 +1,7 @@
import 'alltypes.proto'; import 'alltypes.proto';
extend AllTypes { extend AllTypes {
optional int32 AllTypes_extensionfield1 = 255 [default = 5]; optional int32 AllTypes_extensionfield1 = 255;
} }
message ExtensionMessage { message ExtensionMessage {

View File

@@ -10,7 +10,5 @@ dec = env.GetBuildPath('$BUILD/basic_stream/${PROGPREFIX}decode_stream${PROGSUFF
env.RunTest('person_with_extra_field_stream.output', [dec, "person_with_extra_field.pb"]) env.RunTest('person_with_extra_field_stream.output', [dec, "person_with_extra_field.pb"])
env.Compare(["person_with_extra_field_stream.output", "person_with_extra_field.expected"]) env.Compare(["person_with_extra_field_stream.output", "person_with_extra_field.expected"])
# This uses the backwards compatibility alltypes test, so that dec2 = env.GetBuildPath('$BUILD/alltypes/${PROGPREFIX}decode_alltypes${PROGSUFFIX}')
# alltypes_with_extra_fields.pb doesn't have to be remade so often.
dec2 = env.GetBuildPath('$BUILD/backwards_compatibility/${PROGPREFIX}decode_legacy${PROGSUFFIX}')
env.RunTest('alltypes_with_extra_fields.output', [dec2, 'alltypes_with_extra_fields.pb']) env.RunTest('alltypes_with_extra_fields.output', [dec2, 'alltypes_with_extra_fields.pb'])

View File

@@ -5,6 +5,8 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c) env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
@@ -14,16 +16,9 @@ env.NanopbProto(["alltypes", "alltypes.options"])
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_FIELD_16BIT': 1}) opts.Append(CPPDEFINES = {'PB_FIELD_16BIT': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_fields16.o", "$NANOPB/pb_decode.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.c"])
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.c"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -8,24 +8,6 @@ message EmptyMessage {
} }
enum HugeEnum {
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
required int32 int32_min = 1;
required int32 int32_max = 2;
required uint32 uint32_min = 3;
required uint32 uint32_max = 4;
required int64 int64_min = 5;
required int64 int64_max = 6;
required uint64 uint64_min = 7;
required uint64 uint64_max = 8;
required HugeEnum enum_min = 9;
required HugeEnum enum_max = 10;
}
enum MyEnum { enum MyEnum {
Zero = 0; Zero = 0;
First = 1; First = 1;
@@ -101,13 +83,8 @@ 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;
// Check that extreme integer values are handled correctly
required Limits req_limits = 98;
// Just to make sure that the size of the fields has been calculated // 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. // properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 10099; required int32 end = 10099;
extensions 200 to 255;
} }

View File

@@ -5,6 +5,8 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c) env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
@@ -14,16 +16,9 @@ env.NanopbProto(["alltypes", "alltypes.options"])
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_FIELD_32BIT': 1}) opts.Append(CPPDEFINES = {'PB_FIELD_32BIT': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_fields32.o", "$NANOPB/pb_decode.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.c"])
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.c"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -8,24 +8,6 @@ message EmptyMessage {
} }
enum HugeEnum {
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
required int32 int32_min = 1;
required int32 int32_max = 2;
required uint32 uint32_min = 3;
required uint32 uint32_max = 4;
required int64 int64_min = 5;
required int64 int64_max = 6;
required uint64 uint64_min = 7;
required uint64 uint64_max = 8;
required HugeEnum enum_min = 9;
required HugeEnum enum_max = 10;
}
enum MyEnum { enum MyEnum {
Zero = 0; Zero = 0;
First = 1; First = 1;
@@ -101,13 +83,8 @@ 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;
// Check that extreme integer values are handled correctly
required Limits req_limits = 98;
// Just to make sure that the size of the fields has been calculated // 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. // properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 13432099; required int32 end = 13432099;
extensions 200 to 255;
} }

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

@@ -8,7 +8,6 @@
int main() int main()
{ {
uint8_t buffer[512]; uint8_t buffer[512];
size_t size;
/* Create a message with one missing field */ /* Create a message with one missing field */
{ {
@@ -20,14 +19,12 @@ int main()
printf("Encode failed.\n"); printf("Encode failed.\n");
return 1; return 1;
} }
size = stream.bytes_written;
} }
/* Test that it decodes properly if we don't require that field */ /* Test that it decodes properly if we don't require that field */
{ {
MissingField msg = {0}; MissingField msg = {0};
pb_istream_t stream = pb_istream_from_buffer(buffer, size); pb_istream_t stream = pb_istream_from_buffer(buffer, sizeof(buffer));
if (!pb_decode(&stream, MissingField_fields, &msg)) if (!pb_decode(&stream, MissingField_fields, &msg))
{ {
@@ -39,7 +36,7 @@ int main()
/* Test that it does *not* decode properly if we require the field */ /* Test that it does *not* decode properly if we require the field */
{ {
AllFields msg = {0}; AllFields msg = {0};
pb_istream_t stream = pb_istream_from_buffer(buffer, size); pb_istream_t stream = pb_istream_from_buffer(buffer, sizeof(buffer));
if (pb_decode(&stream, AllFields_fields, &msg)) if (pb_decode(&stream, AllFields_fields, &msg))
{ {

View File

@@ -4,6 +4,8 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.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.c", "$BUILD/alltypes/alltypes.pb.c", c) env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
@@ -13,16 +15,9 @@ env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_NO_ERRMSG': 1}) opts.Append(CPPDEFINES = {'PB_NO_ERRMSG': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_noerr.o", "$NANOPB/pb_decode.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.c"])
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.c"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -5,6 +5,3 @@ pb_callback_t int32_callback;
\sEnumValue1 = 1 \sEnumValue1 = 1
Message5_EnumValue1 Message5_EnumValue1
} pb_packed my_packed_struct; } pb_packed my_packed_struct;
! skipped_field
! SkippedMessage

View File

@@ -63,15 +63,11 @@ message my_packed_struct
} }
// Message with ignored field // Message with ignored field
// Note: doesn't really test if the field is missing in the output,
// but atleast tests that the output compiles.
message Message6 message Message6
{ {
required int32 field1 = 1; required int32 field1 = 1;
optional int32 skipped_field = 2 [(nanopb).type = FT_IGNORE]; optional int32 field2 = 2 [(nanopb).type = FT_IGNORE];
} }
// Message that is skipped
message SkippedMessage
{
option (nanopb_msgopt).skip_message = true;
required int32 foo = 1;
}

View File

@@ -1,36 +0,0 @@
# Check that alltypes test case works also when the .proto file defines
# a package name.
Import("env")
# Build a modified alltypes.proto
def modify_proto(target, source, env):
'''Add a "package test.package;" directive to the beginning of the .proto file.'''
data = open(str(source[0]), 'r').read()
open(str(target[0]), 'w').write("package test.package;\n\n" + data)
return 0
env.Command("alltypes.proto", "#alltypes/alltypes.proto", modify_proto)
env.Command("alltypes.options", "#alltypes/alltypes.options", Copy("$TARGET", "$SOURCE"))
env.NanopbProto(["alltypes", "alltypes.options"])
# Build a modified encode_alltypes.c
def modify_c(target, source, env):
'''Add package name to type names in .c file.'''
data = open(str(source[0]), 'r').read()
type_names = ['AllTypes', 'MyEnum', 'HugeEnum']
for name in type_names:
data = data.replace(name, 'test_package_' + name)
open(str(target[0]), 'w').write(data)
return 0
env.Command("encode_alltypes.c", "#alltypes/encode_alltypes.c", modify_c)
# 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"])
refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX"
env.RunTest(enc)
env.Compare(["encode_alltypes.output", "$BUILD/alltypes/encode_alltypes.output"])

View File

@@ -1,9 +0,0 @@
# Regression test for Issue 125: Wrong identifier name for extension fields
Import("env")
env.NanopbProto(["extensionbug", "extensionbug.options"])
env.Object('extensionbug.pb.c')
env.Match(['extensionbug.pb.h', 'extensionbug.expected'])

View File

@@ -1,3 +0,0 @@
pb_extension_type_t Message2_extras
uint32_t field2

View File

@@ -1,4 +0,0 @@
* type:FT_IGNORE
Message2.extras type:FT_STATIC
Message2.field2 type:FT_STATIC

View File

@@ -1,16 +0,0 @@
message Message1
{
optional uint32 fieldA = 1;
extensions 30 to max;
}
message Message2
{
extend Message1
{
optional Message2 extras = 30;
}
optional uint32 field1 = 1;
optional uint32 field2 = 2;
}

View File

@@ -19,24 +19,15 @@ def add_nanopb_builders(env):
else: else:
infile = None infile = None
if env.has_key("COMMAND"): pipe = subprocess.Popen(str(source[0]),
args = [env["COMMAND"]]
else:
args = [str(source[0])]
if env.has_key('ARGS'):
args.extend(env['ARGS'])
print 'Command line: ' + str(args)
pipe = subprocess.Popen(args,
stdin = infile, stdin = infile,
stdout = open(str(target[0]), 'w'), stdout = open(str(target[0]), 'w'),
stderr = sys.stderr) stderr = sys.stderr)
result = pipe.wait() result = pipe.wait()
if result == 0: if result == 0:
print '\033[32m[ OK ]\033[0m Ran ' + args[0] print '\033[32m[ OK ]\033[0m Ran ' + str(source[0])
else: else:
print '\033[31m[FAIL]\033[0m Program ' + args[0] + ' returned ' + str(result) print '\033[31m[FAIL]\033[0m Program ' + str(source[0]) + ' returned ' + str(result)
return result return result
run_test_builder = Builder(action = run_test, run_test_builder = Builder(action = run_test,
@@ -54,17 +45,6 @@ def add_nanopb_builders(env):
suffix = '.decoded') suffix = '.decoded')
env.Append(BUILDERS = {'Decode': decode_builder}) env.Append(BUILDERS = {'Decode': decode_builder})
# Build command that encodes a message using protoc
def encode_actions(source, target, env, for_signature):
esc = env['ESCAPE']
dirs = ' '.join(['-I' + esc(env.GetBuildPath(d)) for d in env['PROTOCPATH']])
return '$PROTOC $PROTOCFLAGS %s --encode=%s %s <%s >%s' % (
dirs, env['MESSAGE'], esc(str(source[1])), esc(str(source[0])), esc(str(target[0])))
encode_builder = Builder(generator = encode_actions,
suffix = '.encoded')
env.Append(BUILDERS = {'Encode': encode_builder})
# Build command that asserts that two files be equal # Build command that asserts that two files be equal
def compare_files(target, source, env): def compare_files(target, source, env):
data1 = open(str(source[0]), 'rb').read() data1 = open(str(source[0]), 'rb').read()
@@ -85,20 +65,9 @@ def add_nanopb_builders(env):
data = open(str(source[0]), 'rU').read() data = open(str(source[0]), 'rU').read()
patterns = open(str(source[1])) patterns = open(str(source[1]))
for pattern in patterns: for pattern in patterns:
if pattern.strip(): if pattern.strip() and not re.search(pattern.strip(), data, re.MULTILINE):
invert = False print '\033[31m[FAIL]\033[0m Pattern not found in ' + str(source[0]) + ': ' + pattern
if pattern.startswith('! '): return 1
invert = True
pattern = pattern[2:]
status = re.search(pattern.strip(), data, re.MULTILINE)
if not status and not invert:
print '\033[31m[FAIL]\033[0m Pattern not found in ' + str(source[0]) + ': ' + pattern
return 1
elif status and invert:
print '\033[31m[FAIL]\033[0m Pattern should not exist, but does in ' + str(source[0]) + ': ' + pattern
return 1
else: else:
print '\033[32m[ OK ]\033[0m All patterns found in ' + str(source[0]) print '\033[32m[ OK ]\033[0m All patterns found in ' + str(source[0])
return 0 return 0

View File

@@ -57,16 +57,16 @@ def _detect_protoc(env):
# Use protoc defined by user # Use protoc defined by user
return env['PROTOC'] return env['PROTOC']
n = _detect_nanopb(env) p = _detect_nanopb(env)
p1 = os.path.join(n, 'generator-bin', 'protoc' + env['PROGSUFFIX']) p1 = os.path.join(p, 'generator-bin', 'protoc')
if os.path.exists(p1): if os.path.exists(p1):
# Use protoc bundled with binary package # Use protoc bundled with binary package
return env['ESCAPE'](p1) return p1
p = env.WhereIs('protoc') p = env.WhereIs('protoc')
if p: if p:
# Use protoc from path # Use protoc from path
return env['ESCAPE'](p) return p
raise SCons.Errors.StopError(NanopbWarning, raise SCons.Errors.StopError(NanopbWarning,
"Could not find the protoc compiler") "Could not find the protoc compiler")
@@ -78,8 +78,7 @@ def _detect_protocflags(env):
p = _detect_protoc(env) p = _detect_protoc(env)
n = _detect_nanopb(env) n = _detect_nanopb(env)
p1 = os.path.join(n, 'generator-bin', 'protoc' + env['PROGSUFFIX']) if p == os.path.join(n, 'generator-bin', 'protoc'):
if p == env['ESCAPE'](p1):
# Using the bundled protoc, no options needed # Using the bundled protoc, no options needed
return '' return ''

View File

@@ -1,16 +0,0 @@
# Check the nanopb core using splint
Import('env')
p = env.WhereIs('splint')
if p:
env.Command('pb_decode.splint', '$NANOPB/pb_decode.c',
'splint -f splint/splint.rc $SOURCE 2> $TARGET')
env.Command('pb_encode.splint', '$NANOPB/pb_encode.c',
'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

@@ -1,37 +0,0 @@
+checks
+partial
+matchanyintegral
+strictlib
-nullassign
-predboolint
-predboolptr
+ptrnegate
-switchloopbreak
+ignoresigns
-infloopsuncon
-type
# splint's memory checks don't quite work without annotations
-mustfreeonly
-compmempass
-nullret
-observertrans
-statictrans
-compdestroy
-nullpass
-nullstate
-compdef
-usereleased
-temptrans
-dependenttrans
-kepttrans
-branchstate
-immediatetrans
-mustfreefresh
# These tests give false positives, compiler typically has
# better warnings for these.
-noret
-noeffect
-usedef

View File

@@ -34,10 +34,10 @@ LIBPROTOC=$(ldd `which protoc` | grep -o '/.*libprotoc[^ ]*')
cp $LIBPROTOC $DEST/generator-bin/ cp $LIBPROTOC $DEST/generator-bin/
cat > $DEST/generator-bin/protoc << EOF cat > $DEST/generator-bin/protoc << EOF
#!/bin/bash #!/bin/bash
SCRIPTDIR=\$(dirname "\$0") SCRIPTDIR=\$(dirname \$(readlink -f \$0))
export LD_LIBRARY_PATH=\$SCRIPTDIR export LD_LIBRARY_PATH=\$SCRIPTDIR
export PATH=\$SCRIPTDIR:\$PATH export PATH=\$SCRIPTDIR:\$PATH
exec "\$SCRIPTDIR/protoc.bin" "\$@" exec \$SCRIPTDIR/protoc.bin "\$@"
EOF EOF
chmod +x $DEST/generator-bin/protoc chmod +x $DEST/generator-bin/protoc

View File

@@ -37,13 +37,13 @@ LIBPROTOBUF=$(otool -L `which protoc` | grep -o '/.*libprotobuf[^ ]*')
cp $LIBPROTOC $LIBPROTOBUF $DEST/generator-bin/ cp $LIBPROTOC $LIBPROTOBUF $DEST/generator-bin/
cat > $DEST/generator-bin/protoc << EOF cat > $DEST/generator-bin/protoc << EOF
#!/bin/bash #!/bin/bash
SCRIPTDIR=\$(dirname "\$0") SCRIPTDIR=\$(cd \$(dirname \$0); pwd)
export DYLD_LIBRARY_PATH=\$SCRIPTDIR export DYLD_LIBRARY_PATH=\$SCRIPTDIR
export PATH=\$SCRIPTDIR:\$PATH export PATH=\$SCRIPTDIR:\$PATH
exec "\$SCRIPTDIR/protoc.bin" "\$@" exec \$SCRIPTDIR/protoc.bin "\$@"
EOF EOF
chmod +x $DEST/generator-bin/protoc chmod +x $DEST/generator-bin/protoc
# Tar it all up # Tar it all up
( cd dist; zip -r $VERSION.zip $VERSION ) ( cd dist; tar -czf $VERSION.tgz $VERSION )