Compare commits
48 Commits
dev_instal
...
nanopb-0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
906c8283b5 | ||
|
|
4546bb92dc | ||
|
|
18e71bbfe2 | ||
|
|
585cd0356e | ||
|
|
bb51ee655b | ||
|
|
125b49bf24 | ||
|
|
da8210b947 | ||
|
|
10ef575d46 | ||
|
|
7c9a8a132b | ||
|
|
ae7b9a3bd3 | ||
|
|
156139f112 | ||
|
|
26f7341094 | ||
|
|
2b334015af | ||
|
|
435ccbfdf7 | ||
|
|
b1cb035373 | ||
|
|
6d0e0695d0 | ||
|
|
dde71cb426 | ||
|
|
1fc90ab4c4 | ||
|
|
440a53f859 | ||
|
|
3bdbd4dc48 | ||
|
|
8be8b7e41a | ||
|
|
94422ad456 | ||
|
|
1d42f72f40 | ||
|
|
2abd27c91c | ||
|
|
6e08773153 | ||
|
|
d7cadaa46f | ||
|
|
d344bda28a | ||
|
|
05e2dc20f3 | ||
|
|
c61660b3ea | ||
|
|
45c1a32e50 | ||
|
|
ef31774cd9 | ||
|
|
480b39cc0a | ||
|
|
ec517e2108 | ||
|
|
8c2dda67a1 | ||
|
|
58b3a22d6d | ||
|
|
356535da9b | ||
|
|
f4146edf01 | ||
|
|
8da15d8b80 | ||
|
|
bc4ded3b43 | ||
|
|
ef07635e35 | ||
|
|
25516b0591 | ||
|
|
414e637867 | ||
|
|
4ae3b2e566 | ||
|
|
4f37c083d5 | ||
|
|
ed93db08dc | ||
|
|
cd9004089f | ||
|
|
ee5b12c537 | ||
|
|
9cc19a5e99 |
@@ -1,3 +1,10 @@
|
|||||||
|
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.
|
||||||
|
|||||||
@@ -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 or Linux
|
If you have downloaded a binary package for nanopb (either Windows, Linux or
|
||||||
version), the 'protoc' binary is included in the 'generator-bin' folder. In
|
Mac OS X version), the 'protoc' binary is included in the 'generator-bin'
|
||||||
this case, you are ready to go. Simply run this command:
|
folder. In 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
|
||||||
|
|
||||||
|
|||||||
@@ -104,11 +104,12 @@ 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 *compat/pb_syshdr.h* instead. It contains an example of how to provide
|
file *extra/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* to be the name of your custom
|
To use the pb_syshdr.h, define *PB_SYSTEM_HEADER* as *"pb_syshdr.h"* (including the quotes).
|
||||||
header file. It should provide all the dependencies listed above.
|
Similarly, you can provide a custom include file, which should provide all the dependencies
|
||||||
|
listed above.
|
||||||
|
|
||||||
Running the test cases
|
Running the test cases
|
||||||
======================
|
======================
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -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.2.5-dev"
|
nanopb_version = "nanopb-0.2.5"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -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', 5),
|
FieldD.TYPE_INT32: ('int32_t', 'INT32', 10),
|
||||||
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),
|
||||||
@@ -195,6 +195,34 @@ 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]
|
||||||
@@ -206,19 +234,18 @@ 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'
|
||||||
if self.max_size is None:
|
self.ctype = 'char'
|
||||||
can_be_static = False
|
if self.allocation == 'STATIC':
|
||||||
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.max_size is None:
|
if self.allocation == 'STATIC':
|
||||||
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_ptr_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)
|
||||||
@@ -226,35 +253,31 @@ 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):
|
||||||
if self.rules == 'OPTIONAL' and self.allocation == 'STATIC':
|
result = ''
|
||||||
result = ' bool has_' + self.name + ';\n'
|
if self.allocation == 'POINTER':
|
||||||
elif self.rules == 'REPEATED' and self.allocation == 'STATIC':
|
if self.rules == 'REPEATED':
|
||||||
result = ' 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 == 'STRING':
|
||||||
|
# String 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:
|
||||||
result = ''
|
if self.rules == 'OPTIONAL' and self.allocation == 'STATIC':
|
||||||
result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl)
|
result += ' bool has_' + self.name + ';\n'
|
||||||
|
elif self.rules == 'REPEATED' and self.allocation == 'STATIC':
|
||||||
|
result += ' 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):
|
||||||
@@ -309,7 +332,7 @@ class Field:
|
|||||||
result = ' PB_FIELD2(%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 += '%s, ' % self.allocation
|
result += '%-8s, ' % 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
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ 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.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,4 +9,5 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
exec python $(dirname $0)/nanopb_generator.py --protoc-plugin
|
MYPATH=$(dirname "$0")
|
||||||
|
exec python "$MYPATH/nanopb_generator.py" --protoc-plugin
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
59
pb.h
59
pb.h
@@ -43,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.2.5-dev
|
#define NANOPB_VERSION nanopb-0.2.5
|
||||||
|
|
||||||
/* 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:
|
||||||
@@ -116,11 +116,6 @@
|
|||||||
/* 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;
|
||||||
@@ -128,32 +123,33 @@ typedef uint8_t pb_type_t;
|
|||||||
/**** Field data types ****/
|
/**** Field data types ****/
|
||||||
|
|
||||||
/* Numeric types */
|
/* Numeric types */
|
||||||
#define PB_LTYPE_VARINT 0x00 /* int32, uint32, int64, uint64, bool, enum */
|
#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */
|
||||||
#define PB_LTYPE_SVARINT 0x01 /* sint32, sint64 */
|
#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */
|
||||||
#define PB_LTYPE_FIXED32 0x02 /* fixed32, sfixed32, float */
|
#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */
|
||||||
#define PB_LTYPE_FIXED64 0x03 /* fixed64, sfixed64, double */
|
#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */
|
||||||
|
#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 0x03
|
#define PB_LTYPE_LAST_PACKABLE 0x04
|
||||||
|
|
||||||
/* 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 0x04
|
#define PB_LTYPE_BYTES 0x05
|
||||||
|
|
||||||
/* 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 0x05
|
#define PB_LTYPE_STRING 0x06
|
||||||
|
|
||||||
/* Submessage
|
/* Submessage
|
||||||
* submsg_fields is pointer to field descriptions */
|
* submsg_fields is pointer to field descriptions */
|
||||||
#define PB_LTYPE_SUBMESSAGE 0x06
|
#define PB_LTYPE_SUBMESSAGE 0x07
|
||||||
|
|
||||||
/* 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 0x07
|
#define PB_LTYPE_EXTENSION 0x08
|
||||||
|
|
||||||
/* Number of declared LTYPES */
|
/* Number of declared LTYPES */
|
||||||
#define PB_LTYPES_COUNT 8
|
#define PB_LTYPES_COUNT 9
|
||||||
#define PB_LTYPE_MASK 0x0F
|
#define PB_LTYPE_MASK 0x0F
|
||||||
|
|
||||||
/**** Field repetition rules ****/
|
/**** Field repetition rules ****/
|
||||||
@@ -166,6 +162,7 @@ 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
|
||||||
|
|
||||||
@@ -231,9 +228,17 @@ struct _pb_bytes_array_t {
|
|||||||
size_t size;
|
size_t size;
|
||||||
uint8_t bytes[1];
|
uint8_t bytes[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _pb_bytes_array_t pb_bytes_array_t;
|
typedef struct _pb_bytes_array_t pb_bytes_array_t;
|
||||||
|
|
||||||
|
/* Same, except for pointer-type fields. There is no need to variable struct
|
||||||
|
* length in this case.
|
||||||
|
*/
|
||||||
|
struct _pb_bytes_ptr_t {
|
||||||
|
size_t size;
|
||||||
|
uint8_t *bytes;
|
||||||
|
};
|
||||||
|
typedef struct _pb_bytes_ptr_t pb_bytes_ptr_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
|
||||||
* calls pb_decode.
|
* calls pb_decode.
|
||||||
@@ -370,6 +375,22 @@ struct _pb_extension_t {
|
|||||||
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, \
|
||||||
@@ -410,8 +431,8 @@ struct _pb_extension_t {
|
|||||||
#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_VARINT
|
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
|
||||||
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_VARINT
|
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
|
||||||
#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.
|
||||||
|
|||||||
24
pb_decode.c
24
pb_decode.c
@@ -47,7 +47,8 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_exten
|
|||||||
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 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_iterator_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 pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);
|
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);
|
||||||
|
static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);
|
||||||
static bool checkreturn pb_dec_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);
|
||||||
@@ -62,6 +63,7 @@ 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,
|
||||||
@@ -823,8 +825,24 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo
|
|||||||
|
|
||||||
switch (field->data_size)
|
switch (field->data_size)
|
||||||
{
|
{
|
||||||
case 1: *(uint8_t*)dest = (uint8_t)value; break;
|
case 1: *(int8_t*)dest = (int8_t)value; break;
|
||||||
case 2: *(uint16_t*)dest = (uint16_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkreturn pb_dec_uvarint(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 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");
|
||||||
|
|||||||
105
pb_encode.c
105
pb_encode.c
@@ -28,6 +28,7 @@ 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);
|
||||||
@@ -40,6 +41,7 @@ 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,
|
||||||
@@ -117,7 +119,7 @@ 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 (count > field->array_size)
|
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && 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. */
|
||||||
@@ -170,8 +172,22 @@ 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))
|
|
||||||
return false;
|
/* Normally the data is stored directly in the array entries, but
|
||||||
|
* for pointer-type string fields, the array entries are actually
|
||||||
|
* string pointers. So we have to dereference once more to get to
|
||||||
|
* the character data. */
|
||||||
|
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
|
||||||
|
PB_LTYPE(field->type) == PB_LTYPE_STRING)
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,25 +195,38 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode a field with static allocation, i.e. one whose data is stored
|
/* Encode a field with static or pointer allocation, i.e. one whose data
|
||||||
* in the structure itself. */
|
* is available to the encoder directly. */
|
||||||
static bool checkreturn encode_static_field(pb_ostream_t *stream,
|
static bool checkreturn encode_basic_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 dummy = true;
|
bool implicit_has = 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 = &dummy;
|
pSize = &implicit_has;
|
||||||
|
|
||||||
|
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))
|
||||||
@@ -255,7 +284,8 @@ 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:
|
||||||
return encode_static_field(stream, field, pData);
|
case PB_ATYPE_POINTER:
|
||||||
|
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);
|
||||||
@@ -312,7 +342,10 @@ bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], cons
|
|||||||
while (field->tag != 0)
|
while (field->tag != 0)
|
||||||
{
|
{
|
||||||
pData = (const char*)pData + prev_size + field->data_offset;
|
pData = (const char*)pData + prev_size + field->data_offset;
|
||||||
prev_size = field->data_size;
|
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
|
||||||
|
prev_size = sizeof(const void*);
|
||||||
|
else
|
||||||
|
prev_size = field->data_size;
|
||||||
|
|
||||||
/* Special case for static arrays */
|
/* Special case for static arrays */
|
||||||
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
|
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
|
||||||
@@ -424,6 +457,7 @@ 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;
|
||||||
@@ -465,7 +499,12 @@ 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;
|
||||||
|
|
||||||
@@ -505,13 +544,29 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie
|
|||||||
/* Field encoders */
|
/* Field encoders */
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
@@ -548,20 +603,32 @@ bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, c
|
|||||||
|
|
||||||
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;
|
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
|
||||||
|
{
|
||||||
|
const pb_bytes_ptr_t *bytes = (const pb_bytes_ptr_t*)src;
|
||||||
|
return pb_encode_string(stream, bytes->bytes, bytes->size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
|
||||||
|
if (bytes->size + offsetof(pb_bytes_array_t, bytes) > field->data_size)
|
||||||
|
PB_RETURN_ERROR(stream, "bytes size exceeded");
|
||||||
|
|
||||||
if (bytes->size + offsetof(pb_bytes_array_t, bytes) > field->data_size)
|
return pb_encode_string(stream, bytes->bytes, bytes->size);
|
||||||
PB_RETURN_ERROR(stream, "bytes size exceeded");
|
}
|
||||||
|
|
||||||
return pb_encode_string(stream, bytes->bytes, bytes->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
/* strnlen() is not always available, so just use a loop */
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
size_t max_size = field->data_size;
|
||||||
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;
|
||||||
|
|
||||||
|
while (size < max_size && *p != '\0')
|
||||||
{
|
{
|
||||||
size++;
|
size++;
|
||||||
p++;
|
p++;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ if not env.GetOption('clean'):
|
|||||||
string = conf.CheckCHeader('string.h')
|
string = conf.CheckCHeader('string.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 = "#../compat")
|
conf.env.Append(CPPPATH = "#../extra")
|
||||||
|
|
||||||
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})
|
||||||
|
|||||||
@@ -7,6 +7,29 @@ env.NanopbProto(["alltypes", "alltypes.options"])
|
|||||||
enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.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"])
|
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"])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,24 @@ 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;
|
||||||
@@ -39,26 +57,26 @@ message AllTypes {
|
|||||||
required EmptyMessage req_emptymsg = 18;
|
required EmptyMessage req_emptymsg = 18;
|
||||||
|
|
||||||
|
|
||||||
repeated int32 rep_int32 = 21;
|
repeated int32 rep_int32 = 21 [packed = true];
|
||||||
repeated int64 rep_int64 = 22;
|
repeated int64 rep_int64 = 22 [packed = true];
|
||||||
repeated uint32 rep_uint32 = 23;
|
repeated uint32 rep_uint32 = 23 [packed = true];
|
||||||
repeated uint64 rep_uint64 = 24;
|
repeated uint64 rep_uint64 = 24 [packed = true];
|
||||||
repeated sint32 rep_sint32 = 25;
|
repeated sint32 rep_sint32 = 25 [packed = true];
|
||||||
repeated sint64 rep_sint64 = 26;
|
repeated sint64 rep_sint64 = 26 [packed = true];
|
||||||
repeated bool rep_bool = 27;
|
repeated bool rep_bool = 27 [packed = true];
|
||||||
|
|
||||||
repeated fixed32 rep_fixed32 = 28;
|
repeated fixed32 rep_fixed32 = 28 [packed = true];
|
||||||
repeated sfixed32 rep_sfixed32= 29;
|
repeated sfixed32 rep_sfixed32= 29 [packed = true];
|
||||||
repeated float rep_float = 30;
|
repeated float rep_float = 30 [packed = true];
|
||||||
|
|
||||||
repeated fixed64 rep_fixed64 = 31;
|
repeated fixed64 rep_fixed64 = 31 [packed = true];
|
||||||
repeated sfixed64 rep_sfixed64= 32;
|
repeated sfixed64 rep_sfixed64= 32 [packed = true];
|
||||||
repeated double rep_double = 33;
|
repeated double rep_double = 33 [packed = true];
|
||||||
|
|
||||||
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;
|
repeated MyEnum rep_enum = 37 [packed = true];
|
||||||
repeated EmptyMessage rep_emptymsg = 38;
|
repeated EmptyMessage rep_emptymsg = 38;
|
||||||
|
|
||||||
optional int32 opt_int32 = 41 [default = 4041];
|
optional int32 opt_int32 = 41 [default = 4041];
|
||||||
@@ -83,6 +101,9 @@ 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;
|
||||||
|
|||||||
@@ -170,6 +170,17 @@ 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;
|
||||||
|
|||||||
@@ -67,6 +67,17 @@ 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 */
|
||||||
|
|||||||
23
tests/alltypes_pointer/SConscript
Normal file
23
tests/alltypes_pointer/SConscript
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Encode the AllTypes message using pointers for all fields, and verify the
|
||||||
|
# output against the normal AllTypes test case.
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
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", "$COMMON/pb_encode.o"])
|
||||||
|
|
||||||
|
refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX"
|
||||||
|
|
||||||
|
# Encode and compare results
|
||||||
|
env.RunTest(enc)
|
||||||
|
env.RunTest("decode_alltypes.output", [refdec, "encode_alltypes_pointer.output"])
|
||||||
|
env.Compare(["encode_alltypes_pointer.output", "$BUILD/alltypes/encode_alltypes.output"])
|
||||||
|
|
||||||
|
# Do the same thing with the optional fields present
|
||||||
|
env.RunTest("optionals.output", enc, ARGS = ['1'])
|
||||||
|
env.RunTest("optionals.decout", [refdec, "optionals.output"], ARGS = ['1'])
|
||||||
|
env.Compare(["optionals.output", "$BUILD/alltypes/optionals.output"])
|
||||||
|
|
||||||
3
tests/alltypes_pointer/alltypes.options
Normal file
3
tests/alltypes_pointer/alltypes.options
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Generate all fields as pointers.
|
||||||
|
* type:FT_POINTER
|
||||||
|
|
||||||
187
tests/alltypes_pointer/encode_alltypes_pointer.c
Normal file
187
tests/alltypes_pointer/encode_alltypes_pointer.c
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/* 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_ptr_t req_bytes = {4, (uint8_t*)"1015"};
|
||||||
|
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"};
|
||||||
|
pb_bytes_ptr_t rep_bytes[5] = {{0,0}, {0,0}, {0,0}, {0,0}, {4, (uint8_t*)"2015"}};
|
||||||
|
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_ptr_t opt_bytes = {4, (uint8_t*)"3055"};
|
||||||
|
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 = &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 = &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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#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"); \
|
||||||
@@ -176,15 +177,19 @@ 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 */
|
||||||
uint8_t buffer[1024];
|
SET_BINARY_MODE(stdin);
|
||||||
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
|
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 */
|
||||||
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
|
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))
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -10,5 +10,7 @@ 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"])
|
||||||
|
|
||||||
dec2 = env.GetBuildPath('$BUILD/alltypes/${PROGPREFIX}decode_alltypes${PROGSUFFIX}')
|
# This uses the backwards compatibility alltypes test, so that
|
||||||
|
# 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'])
|
||||||
|
|||||||
@@ -8,6 +8,24 @@ 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;
|
||||||
@@ -83,6 +101,9 @@ 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;
|
||||||
|
|||||||
@@ -8,6 +8,24 @@ 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;
|
||||||
@@ -83,6 +101,9 @@ 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;
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ def add_nanopb_builders(env):
|
|||||||
else:
|
else:
|
||||||
infile = None
|
infile = None
|
||||||
|
|
||||||
pipe = subprocess.Popen(str(source[0]),
|
args = [str(source[0])]
|
||||||
|
if env.has_key('ARGS'):
|
||||||
|
args.extend(env['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)
|
||||||
@@ -45,6 +49,17 @@ 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()
|
||||||
|
|||||||
@@ -57,16 +57,16 @@ def _detect_protoc(env):
|
|||||||
# Use protoc defined by user
|
# Use protoc defined by user
|
||||||
return env['PROTOC']
|
return env['PROTOC']
|
||||||
|
|
||||||
p = _detect_nanopb(env)
|
n = _detect_nanopb(env)
|
||||||
p1 = os.path.join(p, 'generator-bin', 'protoc')
|
p1 = os.path.join(n, 'generator-bin', 'protoc' + env['PROGSUFFIX'])
|
||||||
if os.path.exists(p1):
|
if os.path.exists(p1):
|
||||||
# Use protoc bundled with binary package
|
# Use protoc bundled with binary package
|
||||||
return p1
|
return env['ESCAPE'](p1)
|
||||||
|
|
||||||
p = env.WhereIs('protoc')
|
p = env.WhereIs('protoc')
|
||||||
if p:
|
if p:
|
||||||
# Use protoc from path
|
# Use protoc from path
|
||||||
return p
|
return env['ESCAPE'](p)
|
||||||
|
|
||||||
raise SCons.Errors.StopError(NanopbWarning,
|
raise SCons.Errors.StopError(NanopbWarning,
|
||||||
"Could not find the protoc compiler")
|
"Could not find the protoc compiler")
|
||||||
@@ -78,7 +78,8 @@ def _detect_protocflags(env):
|
|||||||
|
|
||||||
p = _detect_protoc(env)
|
p = _detect_protoc(env)
|
||||||
n = _detect_nanopb(env)
|
n = _detect_nanopb(env)
|
||||||
if p == os.path.join(n, 'generator-bin', 'protoc'):
|
p1 = os.path.join(n, 'generator-bin', 'protoc' + env['PROGSUFFIX'])
|
||||||
|
if p == env['ESCAPE'](p1):
|
||||||
# Using the bundled protoc, no options needed
|
# Using the bundled protoc, no options needed
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|||||||
@@ -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 \$(readlink -f \$0))
|
SCRIPTDIR=\$(dirname "\$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
|
||||||
|
|
||||||
|
|||||||
@@ -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=\$(cd \$(dirname \$0); pwd)
|
SCRIPTDIR=\$(dirname "\$0")
|
||||||
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; tar -czf $VERSION.tgz $VERSION )
|
( cd dist; zip -r $VERSION.zip $VERSION )
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user