Compare commits

...

26 Commits

Author SHA1 Message Date
Petteri Aimonen
09ec60cadf Publishing nanopb-0.1.8 2012-12-13 21:29:57 +02:00
Petteri Aimonen
871e5be9dd Fix small error in field callback documentation.
Update issue 44
Status: FixedInGit
2012-12-06 11:13:53 +02:00
Jens Steinhauser
068de05c51 Complete initialization of pb_istream_t.
Because PB_RETURN_ERROR checks if the 'errmsg' member is NULL before
assigning to it, error messages would get lost.
2012-11-27 19:55:21 +02:00
Steffen Siering
1f8fb1f1ed Use TESTS variable to define dependencies for run_unittests 2012-11-16 09:59:04 +02:00
Petteri Aimonen
434dcbb2ee Select compilation options based on $(CC) in tests/Makefile.
Makes 'make CC=clang' work.

Based on patch submitted by Steffen Siering.

Update issue 40:
Status: FixedInGit
2012-11-16 09:51:23 +02:00
Petteri Aimonen
59788e2aab Rename test_compiles.c to test_multiple_files.c 2012-11-16 09:33:11 +02:00
Steffen Siering
cc29958d34 Fix STATIC_ASSERT macro when using multiple .proto files.
The __COUNTER__ macro (used for generating unique names) is at least supported
by gcc, clang and Visual Studio. With this change test_compiles.c is
compilable, since no more typedefs are redefined.

Compilers/Preprocessors not supporting __COUNTER__ error's are still possible
which are hopfully handled by the usage of __LINE__ in most sittuations.

Added unit test for the problem.
2012-11-16 09:24:39 +02:00
Petteri Aimonen
0abb764b18 Fix naming of nested Enums with short names 2012-11-14 00:43:51 +02:00
Petteri Aimonen
02ecee2de8 Fix naming of enums when long_names=false.
Modify test case to check that options.pb.o compiles.

Update issue 42
Status: FixedInGit

Update issue 43
Status: FixedInGit
2012-11-14 00:36:16 +02:00
Petteri Aimonen
332a9ee95c Fix changelog 2012-11-11 11:20:34 +02:00
Petteri Aimonen
fc6f56b2bd Setting version to 0.1.8-dev 2012-11-11 11:19:17 +02:00
Petteri Aimonen
92bb37b074 Publishing nanopb-0.1.7 2012-11-11 11:16:01 +02:00
Petteri Aimonen
ad9a885644 Document new generator options 2012-10-29 19:33:33 +02:00
Petteri Aimonen
08391f35ee Add nanopb version number to generated files.
tools/set_version.sh is used to update the values.

Update issue 36
Status: FixedInGit
2012-10-29 19:15:34 +02:00
Petteri Aimonen
3aaa4ad8c2 Add extern "C" to header files.
Update issue 35
Status: FixedInGit
2012-10-29 19:03:19 +02:00
Petteri Aimonen
db1eefc24b Add option to use short names for enum values.
Update issue 38
Status: FixedInGit
2012-10-29 18:55:49 +02:00
Petteri Aimonen
0ee4bb96b1 Allow defining field type in .proto.
Update issue 30
Status: FixedInGit
2012-10-29 18:34:24 +02:00
Petteri Aimonen
28b0136ea4 Improve .proto options parsing.
Options can now be defined on command line, file, message or in field
scope.

Update issue 12
Status: Started
2012-10-29 18:20:15 +02:00
Petteri Aimonen
9e0ee92f0a Use optparse in nanopb_generator.py 2012-10-29 17:25:16 +02:00
Petteri Aimonen
c3fa362653 Give names to generated structures to allow forward declaration.
Update issue 39
Status: FixedInGit
2012-10-29 16:56:45 +02:00
Petteri Aimonen
bffd3a9acc Improve the person_with_extra_field test.
Added a field after the extra field to verify it's also ok.
2012-10-21 21:31:20 +03:00
Petteri Aimonen
dcab39a41c Remove the "buf = NULL" => skip requirement from pb_istream_t callbacks.
Rationale: it's easy to implement the callback wrong. Doing so introduces
io errors when unknown fields are present in the input. If code is not
tested with unknown fields, these bugs can remain hidden for long time.

Added a special case for the memory buffer stream, where it gives a small
speed benefit.

Added testcase for skipping fields with test_decode2 implementation.

Update issue 37
Status: FixedInGit
2012-10-18 19:45:28 +03:00
Petteri Aimonen
900c8dd125 Add tests for negative values in the alltypes testcase. 2012-10-14 12:27:08 +03:00
Petteri Aimonen
3f563792ad Add buffer size check in test_decode1.c example.
This check gives a better error message in case you test stuff
and have a message longer than 512 bytes.

Update issue 34
Status: FixedInGit
2012-09-18 16:51:22 +03:00
Petteri Aimonen
b214de4e1e Enable -Wconversion for core and fix the warnings.
This should help avoid issue 33 in the future.
2012-09-03 17:35:14 +03:00
dch
be78e3b4d0 Fix build warnings on MS compilers
Update issue 33
Status: FixedInGit
2012-09-03 17:18:49 +03:00
23 changed files with 577 additions and 152 deletions

View File

@@ -1,3 +1,19 @@
nanopb-0.1.8
Fix bugs in the enum short names introduced in 0.1.7 (issues 42, 43)
Fix STATIC_ASSERT macro when using multiple .proto files. (issue 41)
Fix missing initialization of istream.errmsg
Make tests/Makefile work for non-gcc compilers (issue 40)
nanopb-0.1.7
Remove "skip" mode from pb_istream_t callbacks. Example implementation had a bug. (issue 37)
Add option to use shorter names for enum values (issue 38)
Improve options support in generator (issues 12, 30)
Add nanopb version number to generated files (issue 36)
Add extern "C" to generated headers (issue 35)
Add names for structs to allow forward declaration (issue 39)
Add buffer size check in example (issue 34)
Fix build warnings on MS compilers (issue 33)
nanopb-0.1.6
Reorganize the field decoder interface (issue 2)
Improve performance in submessage decoding (issue 28)

View File

@@ -38,6 +38,20 @@ This file, in turn, requires the file *google/protobuf/descriptor.proto*. This i
protoc -I/usr/include -Inanopb/generator -I. -omessage.pb message.proto
The options can be defined in file, message and field scopes::
option (nanopb_fileopt).max_size = 20; // File scope
message Message
{
option (nanopb_msgopt).max_size = 30; // Message scope
required string fieldsize = 1 [(nanopb).max_size = 40]; // Field scope
}
It is also possible to give the options on command line, but then they will affect the whole file. For example::
user@host:~$ python ../generator/nanopb_generator.py -s 'max_size: 20' message.pb
Streams
=======
@@ -92,9 +106,8 @@ Writing to stdout::
Input streams
-------------
For input streams, there are a few extra rules:
For input streams, there is one extra rule:
#) If buf is NULL, read from stream but don't store the data. This is used to skip unknown input.
#) You don't need to know the length of the message in advance. After getting EOF error when reading, set bytes_left to 0 and return false. Pb_decode will detect this and if the EOF was in a proper position, it will return true.
Here is the structure::

View File

@@ -381,7 +381,7 @@ Remove the data for a field from the stream, without actually decoding it::
For decoding numeric (including enumerated and boolean) values, use `pb_decode_varint`_, `pb_decode_svarint`_, `pb_decode_fixed32`_ and `pb_decode_fixed64`_. They take a pointer to a 32- or 64-bit C variable, which you may then cast to smaller datatype for storage.
For decoding strings and bytes fields, the length has already been decoded. You can therefore check the total length in *stream->state* and read the data using `pb_read`_.
For decoding strings and bytes fields, the length has already been decoded. You can therefore check the total length in *stream->bytes_left* and read the data using `pb_read`_.
Finally, for decoding submessages in a callback, simply use `pb_decode`_ and pass it the *SubMessage_fields* descriptor array.

View File

@@ -19,15 +19,6 @@ static bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
int fd = (intptr_t)stream->state;
int result;
if (buf == NULL)
{
/* Well, this is a really inefficient way to skip input. */
/* It is only used when there are unknown fields. */
char dummy;
while (count-- && recv(fd, &dummy, 1, 0) == 1);
return count == 0;
}
result = recv(fd, buf, count, MSG_WAITALL);
if (result == 0)

View File

@@ -7,9 +7,24 @@
import "google/protobuf/descriptor.proto";
enum FieldType {
FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible.
FT_CALLBACK = 1; // Always generate a callback field.
FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
}
message NanoPBOptions {
// Allocated size for 'bytes' and 'string' fields.
optional int32 max_size = 1;
// Allocated number of entries in arrays ('repeated' fields)
optional int32 max_count = 2;
// Force type of field (callback or static allocation)
optional FieldType type = 3 [default = FT_DEFAULT];
// Use long names for enums, i.e. EnumName_EnumValue.
optional bool long_names = 4 [default = true];
}
// Protocol Buffers extension number registry
@@ -20,7 +35,20 @@ message NanoPBOptions {
// Extensions: 1010 (all types)
// --------------------------------
extend google.protobuf.FileOptions {
optional NanoPBOptions nanopb_fileopt = 1010;
}
extend google.protobuf.MessageOptions {
optional NanoPBOptions nanopb_msgopt = 1010;
}
extend google.protobuf.EnumOptions {
optional NanoPBOptions nanopb_enumopt = 1010;
}
extend google.protobuf.FieldOptions {
optional NanoPBOptions nanopb = 1010;
}

View File

@@ -1,4 +1,5 @@
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
nanopb_version = "nanopb-0.1.8"
try:
import google.protobuf.descriptor_pb2 as descriptor
@@ -22,6 +23,16 @@ except:
print
raise
# ---------------------------------------------------------------------------
# Generation of single fields
# ---------------------------------------------------------------------------
import time
import os.path
# Values are tuple (c type, pb ltype)
@@ -62,6 +73,9 @@ class Names:
else:
raise ValueError("Name parts should be of type str")
def __eq__(self, other):
return isinstance(other, Names) and self.parts == other.parts
def names_from_type_name(type_name):
'''Parse Names() from FieldDescriptorProto type_name'''
if type_name[0] != '.':
@@ -69,19 +83,27 @@ def names_from_type_name(type_name):
return Names(type_name[1:].split('.'))
class Enum:
def __init__(self, names, desc):
def __init__(self, names, desc, enum_options):
'''desc is EnumDescriptorProto'''
self.options = enum_options
self.names = names + desc.name
self.values = [(self.names + x.name, x.number) for x in desc.value]
if enum_options.long_names:
self.values = [(self.names + x.name, x.number) for x in desc.value]
else:
self.values = [(names + x.name, x.number) for x in desc.value]
self.value_longnames = [self.names + x.name for x in desc.value]
def __str__(self):
result = 'typedef enum {\n'
result = 'typedef enum _%s {\n' % self.names
result += ',\n'.join([" %s = %d" % x for x in self.values])
result += '\n} %s;' % self.names
return result
class Field:
def __init__(self, struct_name, desc):
def __init__(self, struct_name, desc, field_options):
'''desc is FieldDescriptorProto'''
self.tag = desc.number
self.struct_name = struct_name
@@ -91,28 +113,27 @@ class Field:
self.max_count = None
self.array_decl = ""
# Parse nanopb-specific field options
if desc.options.HasExtension(nanopb_pb2.nanopb):
ext = desc.options.Extensions[nanopb_pb2.nanopb]
if ext.HasField("max_size"):
self.max_size = ext.max_size
if ext.HasField("max_count"):
self.max_count = ext.max_count
# Parse field options
if field_options.HasField("max_size"):
self.max_size = field_options.max_size
if field_options.HasField("max_count"):
self.max_count = field_options.max_count
if desc.HasField('default_value'):
self.default = desc.default_value
# Decide HTYPE
# HTYPE is the high-order nibble of nanopb field description,
# defining whether value is required/optional/repeated.
is_callback = False
can_be_static = True
if desc.label == FieldD.LABEL_REQUIRED:
self.htype = 'PB_HTYPE_REQUIRED'
elif desc.label == FieldD.LABEL_OPTIONAL:
self.htype = 'PB_HTYPE_OPTIONAL'
elif desc.label == FieldD.LABEL_REPEATED:
if self.max_count is None:
is_callback = True
can_be_static = False
else:
self.htype = 'PB_HTYPE_ARRAY'
self.array_decl = '[%d]' % self.max_count
@@ -133,14 +154,14 @@ class Field:
elif desc.type == FieldD.TYPE_STRING:
self.ltype = 'PB_LTYPE_STRING'
if self.max_size is None:
is_callback = True
can_be_static = False
else:
self.ctype = 'char'
self.array_decl += '[%d]' % self.max_size
elif desc.type == FieldD.TYPE_BYTES:
self.ltype = 'PB_LTYPE_BYTES'
if self.max_size is None:
is_callback = True
can_be_static = False
else:
self.ctype = self.struct_name + self.name + 't'
elif desc.type == FieldD.TYPE_MESSAGE:
@@ -149,7 +170,16 @@ class Field:
else:
raise NotImplementedError(desc.type)
if is_callback:
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_CALLBACK:
self.htype = 'PB_HTYPE_CALLBACK'
self.ctype = 'pb_callback_t'
self.array_decl = ''
@@ -264,10 +294,19 @@ class Field:
return max(self.tag, self.max_size, self.max_count)
# ---------------------------------------------------------------------------
# Generation of messages (structures)
# ---------------------------------------------------------------------------
class Message:
def __init__(self, names, desc):
def __init__(self, names, desc, message_options):
self.name = names
self.fields = [Field(self.name, f) for f in desc.field]
self.fields = [Field(self.name, f, get_nanopb_suboptions(f, message_options)) for f in desc.field]
self.ordered_fields = self.fields[:]
self.ordered_fields.sort()
@@ -276,7 +315,7 @@ class Message:
return [str(field.ctype) for field in self.fields]
def __str__(self):
result = 'typedef struct {\n'
result = 'typedef struct _%s {\n' % self.name
result += '\n'.join([str(f) for f in self.ordered_fields])
result += '\n} %s;' % self.name
return result
@@ -313,6 +352,16 @@ class Message:
result += ' PB_LAST_FIELD\n};'
return result
# ---------------------------------------------------------------------------
# Processing of entire .proto files
# ---------------------------------------------------------------------------
def iterate_messages(desc, names = Names()):
'''Recursively find all messages. For each, yield name, DescriptorProto.'''
if hasattr(desc, 'message_type'):
@@ -327,7 +376,7 @@ def iterate_messages(desc, names = Names()):
for x in iterate_messages(submsg, sub_names):
yield x
def parse_file(fdesc):
def parse_file(fdesc, file_options):
'''Takes a FileDescriptorProto and returns tuple (enum, messages).'''
enums = []
@@ -339,12 +388,24 @@ def parse_file(fdesc):
base_name = Names()
for enum in fdesc.enum_type:
enums.append(Enum(base_name, enum))
enum_options = get_nanopb_suboptions(enum, file_options)
enums.append(Enum(base_name, enum, enum_options))
for names, message in iterate_messages(fdesc, base_name):
messages.append(Message(names, message))
message_options = get_nanopb_suboptions(message, file_options)
messages.append(Message(names, message, message_options))
for enum in message.enum_type:
enums.append(Enum(names, enum))
enum_options = get_nanopb_suboptions(enum, message_options)
enums.append(Enum(names, enum, enum_options))
# Fix field default values where enum short names are used.
for enum in enums:
if not enum.options.long_names:
for message in messages:
for field in message.fields:
if field.default in enum.value_longnames:
idx = enum.value_longnames.index(field.default)
field.default = enum.values[idx][0]
return enums, messages
@@ -385,6 +446,7 @@ def generate_header(dependencies, headername, enums, messages):
'''
yield '/* Automatically generated nanopb header */\n'
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
symbol = headername.replace('.', '_').upper()
yield '#ifndef _PB_%s_\n' % symbol
@@ -394,7 +456,10 @@ def generate_header(dependencies, headername, enums, messages):
for dependency in dependencies:
noext = os.path.splitext(dependency)[0]
yield '#include "%s.pb.h"\n' % noext
yield '\n'
yield '#ifdef __cplusplus\n'
yield 'extern "C" {\n'
yield '#endif\n\n'
yield '/* Enum definitions */\n'
for enum in enums:
@@ -428,7 +493,9 @@ def generate_header(dependencies, headername, enums, messages):
worst = 0
worst_field = ''
checks = []
checks_msgnames = []
for msg in messages:
checks_msgnames.append(msg.name)
for field in msg.fields:
status = field.largest_field_value()
if isinstance(status, (str, unicode)):
@@ -446,7 +513,8 @@ def generate_header(dependencies, headername, enums, messages):
yield '#error Field descriptor for %s is too large. Define PB_FIELD_16BIT to fix this.\n' % worst_field
else:
assertion = ' && '.join(str(c) + ' < 256' for c in checks)
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT)\n' % assertion
msgs = '_'.join(str(n) for n in checks_msgnames)
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
yield '#endif\n\n'
if worst > 65535 or checks:
@@ -455,9 +523,14 @@ def generate_header(dependencies, headername, enums, messages):
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)
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT)\n' % assertion
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'
yield '\n#ifdef __cplusplus\n'
yield '} /* extern "C" */\n'
yield '#endif\n'
# End of header
yield '\n#endif\n'
@@ -465,6 +538,7 @@ def generate_source(headername, enums, messages):
'''Generate content for a source file.'''
yield '/* Automatically generated nanopb constant definitions */\n'
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
yield '#include "%s"\n\n' % headername
for msg in messages:
@@ -475,39 +549,105 @@ def generate_source(headername, enums, messages):
for msg in messages:
yield msg.fields_definition() + '\n\n'
if __name__ == '__main__':
import sys
import os.path
# ---------------------------------------------------------------------------
# Command line interface
# ---------------------------------------------------------------------------
import sys
import os.path
from optparse import OptionParser
import google.protobuf.text_format as text_format
optparser = OptionParser(
usage = "Usage: nanopb_generator.py [options] file.pb ...",
epilog = "Compile file.pb from file.proto by: 'protoc -ofile.pb file.proto'. " +
"Output will be written to file.pb.h and file.pb.c.")
optparser.add_option("-x", dest="exclude", metavar="FILE", action="append", default=[],
help="Exclude file from generated #include list.")
optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False,
help="Don't print anything except errors.")
optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
help="Print more information.")
optparser.add_option("-s", dest="settings", metavar="OPTION:VALUE", action="append", default=[],
help="Set generator option (max_size, max_count etc.).")
def get_nanopb_suboptions(subdesc, options):
'''Get copy of options, and merge information from subdesc.'''
new_options = nanopb_pb2.NanoPBOptions()
new_options.CopyFrom(options)
if len(sys.argv) != 2:
print "Usage: " + sys.argv[0] + " file.pb"
print "where file.pb has been compiled from .proto by:"
print "protoc -ofile.pb file.proto"
print "Output fill be written to file.pb.h and file.pb.c"
if isinstance(subdesc.options, descriptor.FieldOptions):
ext_type = nanopb_pb2.nanopb
elif isinstance(subdesc.options, descriptor.FileOptions):
ext_type = nanopb_pb2.nanopb_fileopt
elif isinstance(subdesc.options, descriptor.MessageOptions):
ext_type = nanopb_pb2.nanopb_msgopt
elif isinstance(subdesc.options, descriptor.EnumOptions):
ext_type = nanopb_pb2.nanopb_enumopt
else:
raise Exception("Unknown options type")
if subdesc.options.HasExtension(ext_type):
ext = subdesc.options.Extensions[ext_type]
new_options.MergeFrom(ext)
return new_options
def process(filenames, options):
'''Process the files given on the command line.'''
if not filenames:
optparser.print_help()
return False
if options.quiet:
options.verbose = False
toplevel_options = nanopb_pb2.NanoPBOptions()
for s in options.settings:
text_format.Merge(s, toplevel_options)
for filename in filenames:
data = open(filename, 'rb').read()
fdesc = descriptor.FileDescriptorSet.FromString(data)
file_options = get_nanopb_suboptions(fdesc.file[0], toplevel_options)
if options.verbose:
print "Options for " + filename + ":"
print text_format.MessageToString(file_options)
enums, messages = parse_file(fdesc.file[0], file_options)
noext = os.path.splitext(filename)[0]
headername = noext + '.pb.h'
sourcename = noext + '.pb.c'
headerbasename = os.path.basename(headername)
if not options.quiet:
print "Writing to " + headername + " and " + sourcename
# List of .proto files that should not be included in the C header file
# even if they are mentioned in the source .proto.
excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto'] + options.exclude
dependencies = [d for d in fdesc.file[0].dependency if d not in excludes]
header = open(headername, 'w')
for part in generate_header(dependencies, headerbasename, enums, messages):
header.write(part)
source = open(sourcename, 'w')
for part in generate_source(headerbasename, enums, messages):
source.write(part)
return True
if __name__ == '__main__':
options, filenames = optparser.parse_args()
status = process(filenames, options)
if not status:
sys.exit(1)
data = open(sys.argv[1], 'rb').read()
fdesc = descriptor.FileDescriptorSet.FromString(data)
enums, messages = parse_file(fdesc.file[0])
noext = os.path.splitext(sys.argv[1])[0]
headername = noext + '.pb.h'
sourcename = noext + '.pb.c'
headerbasename = os.path.basename(headername)
print "Writing to " + headername + " and " + sourcename
# List of .proto files that should not be included in the C header file
# even if they are mentioned in the source .proto.
excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto']
dependencies = [d for d in fdesc.file[0].dependency if d not in excludes]
header = open(headername, 'w')
for part in generate_header(dependencies, headerbasename, enums, messages):
header.write(part)
source = open(sourcename, 'w')
for part in generate_source(headerbasename, enums, messages):
source.write(part)

View File

@@ -7,15 +7,70 @@ from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
import google.protobuf.descriptor_pb2
DESCRIPTOR = descriptor.FileDescriptor(
name='nanopb.proto',
package='',
serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"4\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions')
serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"t\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true*;\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\r\n\tFT_STATIC\x10\x02:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions')
_FIELDTYPE = descriptor.EnumDescriptor(
name='FieldType',
full_name='FieldType',
filename=None,
file=DESCRIPTOR,
values=[
descriptor.EnumValueDescriptor(
name='FT_DEFAULT', index=0, number=0,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='FT_CALLBACK', index=1, number=1,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='FT_STATIC', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=168,
serialized_end=227,
)
FT_DEFAULT = 0
FT_CALLBACK = 1
FT_STATIC = 2
NANOPB_FILEOPT_FIELD_NUMBER = 1010
nanopb_fileopt = descriptor.FieldDescriptor(
name='nanopb_fileopt', full_name='nanopb_fileopt', index=0,
number=1010, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=True, extension_scope=None,
options=None)
NANOPB_MSGOPT_FIELD_NUMBER = 1010
nanopb_msgopt = descriptor.FieldDescriptor(
name='nanopb_msgopt', full_name='nanopb_msgopt', index=1,
number=1010, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=True, extension_scope=None,
options=None)
NANOPB_ENUMOPT_FIELD_NUMBER = 1010
nanopb_enumopt = descriptor.FieldDescriptor(
name='nanopb_enumopt', full_name='nanopb_enumopt', index=2,
number=1010, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=True, extension_scope=None,
options=None)
NANOPB_FIELD_NUMBER = 1010
nanopb = descriptor.FieldDescriptor(
name='nanopb', full_name='nanopb', index=0,
name='nanopb', full_name='nanopb', index=3,
number=1010, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
@@ -44,6 +99,20 @@ _NANOPBOPTIONS = descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
descriptor.FieldDescriptor(
name='type', full_name='NanoPBOptions.type', index=2,
number=3, type=14, cpp_type=8, label=1,
has_default_value=True, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
descriptor.FieldDescriptor(
name='long_names', full_name='NanoPBOptions.long_names', index=3,
number=4, type=8, cpp_type=7, label=1,
has_default_value=True, default_value=True,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
@@ -54,11 +123,11 @@ _NANOPBOPTIONS = descriptor.Descriptor(
is_extendable=False,
extension_ranges=[],
serialized_start=50,
serialized_end=102,
serialized_end=166,
)
import google.protobuf.descriptor_pb2
_NANOPBOPTIONS.fields_by_name['type'].enum_type = _FIELDTYPE
DESCRIPTOR.message_types_by_name['NanoPBOptions'] = _NANOPBOPTIONS
class NanoPBOptions(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
@@ -66,6 +135,12 @@ class NanoPBOptions(message.Message):
# @@protoc_insertion_point(class_scope:NanoPBOptions)
nanopb_fileopt.message_type = _NANOPBOPTIONS
google.protobuf.descriptor_pb2.FileOptions.RegisterExtension(nanopb_fileopt)
nanopb_msgopt.message_type = _NANOPBOPTIONS
google.protobuf.descriptor_pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
nanopb_enumopt.message_type = _NANOPBOPTIONS
google.protobuf.descriptor_pb2.EnumOptions.RegisterExtension(nanopb_enumopt)
nanopb.message_type = _NANOPBOPTIONS
google.protobuf.descriptor_pb2.FieldOptions.RegisterExtension(nanopb)
# @@protoc_insertion_point(module_scope)

25
pb.h
View File

@@ -6,6 +6,8 @@
* see pb_encode.h or pb_decode.h
*/
#define NANOPB_VERSION nanopb-0.1.8
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
@@ -22,9 +24,13 @@
#define UNUSED(x) (void)(x)
#endif
/* Compile-time assertion, used for checking compatible compilation options. */
/* Compile-time assertion, used for checking compatible compilation options.
* If this fails on your compiler for some reason, use #define STATIC_ASSERT
* to disable it. */
#ifndef STATIC_ASSERT
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1];
#define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
#define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
#define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER
#endif
/* Number of required fields to keep track of
@@ -75,6 +81,7 @@ typedef enum {
/* Number of declared LTYPES */
PB_LTYPES_COUNT = 7,
PB_LTYPE_MASK = 0x0F,
/******************
* Modifier flags *
@@ -95,11 +102,13 @@ typedef enum {
* data_offset points to pb_callback_t structure.
* LTYPE should be 0 (it is ignored, but sometimes
* used to speculatively index an array). */
PB_HTYPE_CALLBACK = 0x30
PB_HTYPE_CALLBACK = 0x30,
PB_HTYPE_MASK = 0xF0
} pb_packed pb_type_t;
#define PB_HTYPE(x) ((x) & 0xF0)
#define PB_LTYPE(x) ((x) & 0x0F)
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
/* This structure is used in auto-generated constants
* to specify struct fields.
@@ -145,10 +154,12 @@ struct _pb_field_t {
* 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.
*/
typedef struct {
struct _pb_bytes_array_t {
size_t size;
uint8_t bytes[1];
} pb_bytes_array_t;
};
typedef struct _pb_bytes_array_t pb_bytes_array_t;
/* This structure is used for giving the callback function.
* It is stored in the message structure and filled in by the method that

View File

@@ -36,18 +36,6 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
* pb_istream *
**************/
bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
if (stream->bytes_left < count)
PB_RETURN_ERROR(stream, "end-of-stream");
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
stream->bytes_left -= count;
return true;
}
static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
uint8_t *source = (uint8_t*)stream->state;
@@ -59,12 +47,42 @@ static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t coun
return true;
}
bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
if (buf == NULL && stream->callback != buf_read)
{
/* Skip input bytes */
uint8_t tmp[16];
while (count > 16)
{
if (!pb_read(stream, tmp, 16))
return false;
count -= 16;
}
return pb_read(stream, tmp, count);
}
if (stream->bytes_left < count)
PB_RETURN_ERROR(stream, "end-of-stream");
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
stream->bytes_left -= count;
return true;
}
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
{
pb_istream_t stream;
stream.callback = &buf_read;
stream.state = buf;
stream.bytes_left = bufsize;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
return stream;
}
@@ -83,7 +101,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
{
uint8_t byte;
uint8_t bitpos = 0;
int bitpos = 0;
*dest = 0;
while (bitpos < 64 && pb_read(stream, &byte, 1))
@@ -447,7 +465,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
{
fields_seen[iter.required_field_index >> 3] |= 1 << (iter.required_field_index & 7);
fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7));
}
if (!decode_field(stream, wire_type, &iter))
@@ -483,9 +501,9 @@ bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest)
return false;
if (value & 1)
*dest = ~(value >> 1);
*dest = (int64_t)(~(value >> 1));
else
*dest = value >> 1;
*dest = (int64_t)(value >> 1);
return true;
}
@@ -539,9 +557,9 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo
switch (field->data_size)
{
case 1: *(uint8_t*)dest = value; break;
case 2: *(uint16_t*)dest = value; break;
case 4: *(uint32_t*)dest = value; break;
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 8: *(uint64_t*)dest = value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
@@ -556,7 +574,7 @@ bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, v
switch (field->data_size)
{
case 4: *(int32_t*)dest = value; break;
case 4: *(int32_t*)dest = (int32_t)value; break;
case 8: *(int64_t*)dest = value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}

View File

@@ -12,6 +12,10 @@
#include <stdbool.h>
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Lightweight input stream.
* You can provide a callback function for reading or use
* pb_istream_from_buffer.
@@ -19,12 +23,10 @@
* Rules for callback:
* 1) Return false on IO errors. This will cause decoding to abort.
*
* 2) If buf is NULL, read but don't store bytes ("skip input").
*
* 3) You can use state to store your own data (e.g. buffer pointer),
* 2) You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
*
* 4) Your callback may be used with substreams, in which case bytes_left
* 3) Your callback may be used with substreams, in which case bytes_left
* is different than from the main stream. Don't use bytes_left to compute
* any pointers.
*/
@@ -104,4 +106,8 @@ bool pb_skip_varint(pb_istream_t *stream);
bool pb_skip_string(pb_istream_t *stream);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -205,7 +205,7 @@ bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], cons
bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
{
uint8_t buffer[10];
int i = 0;
size_t i = 0;
if (value == 0)
return pb_write(stream, (uint8_t*)&value, 1);
@@ -225,9 +225,9 @@ bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
{
uint64_t zigzagged;
if (value < 0)
zigzagged = ~(value << 1);
zigzagged = (uint64_t)(~(value << 1));
else
zigzagged = value << 1;
zigzagged = (uint64_t)(value << 1);
return pb_encode_varint(stream, zigzagged);
}
@@ -266,7 +266,7 @@ bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
#endif
}
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, int field_number)
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
{
uint64_t tag = wiretype | (field_number << 3);
return pb_encode_varint(stream, tag);
@@ -370,7 +370,7 @@ bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, co
bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
uint64_t value = 0;
int64_t value = 0;
switch (field->data_size)
{

View File

@@ -9,6 +9,10 @@
#include <stdbool.h>
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Lightweight output stream.
* You can provide callback for writing or use pb_ostream_from_buffer.
*
@@ -54,7 +58,7 @@ bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field);
/* Encode field header by manually specifing wire type. You need to use this if
* you want to write out packed arrays from a callback field. */
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, int field_number);
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
/* Encode an integer in the varint format.
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
@@ -99,5 +103,8 @@ bool pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *sr
* instead, it has the same functionality with a less confusing interface. */
bool pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -1,15 +1,30 @@
CFLAGS=-ansi -Wall -Werror -I .. -g -O0 --coverage
LDFLAGS=--coverage
DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h callbacks.pb.h unittests.h unittestproto.pb.h alltypes.pb.h missing_fields.pb.h
TESTS=test_decode1 test_encode1 decode_unittests encode_unittests test_no_messages
CFLAGS=-ansi -Wall -Werror -I .. -g -O0
DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h \
callbacks2.pb.h callbacks.pb.h unittests.h unittestproto.pb.h \
alltypes.pb.h missing_fields.pb.h
TESTS= decode_unittests encode_unittests \
test_decode1 test_decode2 test_decode3 \
test_encode1 test_encode2 test_encode3 \
test_decode_callbacks test_encode_callbacks \
test_missing_fields test_no_messages \
test_multiple_files test_cxxcompile test_options
# More strict checks for the core part of nanopb
CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wlogical-op
CC_VERSION=$(shell $(CC) -v 2>&1)
CFLAGS_CORE=
ifneq (,$(findstring gcc,$(CC_VERSION)))
CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wlogical-op -Wconversion
CFLAGS+=--coverage
LDFLAGS+=--coverage
endif
ifneq (,$(findstring clang,$(CC_VERSION)))
CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wconversion
endif
all: breakpoints $(TESTS) run_unittests
clean:
rm -f $(TESTS) person.pb* alltypes.pb* *.o *.gcda *.gcno
rm -f $(TESTS) person.pb* alltypes.pb* *.o *.gcda *.gcno *.pb.h *.pb.c
%.pb.o: %.pb.c %.pb.h
$(CC) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
@@ -35,6 +50,7 @@ test_decode3: test_decode3.o pb_decode.o alltypes.pb.o
test_encode1: test_encode1.o pb_encode.o person.pb.o
test_encode2: test_encode2.o pb_encode.o person.pb.o
test_encode3: test_encode3.o pb_encode.o alltypes.pb.o
test_multiple_files: test_multiple_files.o pb_encode.o callbacks2.pb.o callbacks.pb.o
test_decode_callbacks: test_decode_callbacks.o pb_decode.o callbacks.pb.o
test_encode_callbacks: test_encode_callbacks.o pb_encode.o callbacks.pb.o
test_missing_fields: test_missing_fields.o pb_encode.o pb_decode.o missing_fields.pb.o
@@ -55,7 +71,7 @@ coverage: run_unittests
gcov pb_encode.gcda
gcov pb_decode.gcda
run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 test_encode2 test_encode3 test_decode1 test_decode2 test_decode3 test_encode_callbacks test_decode_callbacks test_missing_fields
run_unittests: $(TESTS)
rm -f *.gcda
./decode_unittests > /dev/null
@@ -70,6 +86,9 @@ run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 te
[ "`./test_encode2 | ./test_decode2`" = \
"`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ]
[ "`./test_decode2 < person_with_extra_field.pb`" = \
"`./test_encode2 | ./test_decode2`" ]
[ "`./test_encode_callbacks | ./test_decode_callbacks`" = \
"`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ]
@@ -79,5 +98,13 @@ run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 te
./test_missing_fields
test_options: options.pb.h options.expected options.pb.o
cat options.expected | while read -r p; do \
if ! grep -q "$$p" $<; then \
echo Expected: "$$p"; \
exit 1; \
fi \
done
run_fuzztest: test_decode2
bash -c 'I=1; while true; do cat /dev/urandom | ./test_decode2 > /dev/null; I=$$(($$I+1)); echo -en "\r$$I"; done'

9
tests/callbacks2.proto Normal file
View File

@@ -0,0 +1,9 @@
// Test if including generated header file for this file + implicit include of
// callbacks.pb.h still compiles. Used with test_compiles.c.
import "callbacks.proto";
message Callback2Message {
required TestMessage tstmsg = 1;
required SubMessage submsg = 2;
}

6
tests/options.expected Normal file
View File

@@ -0,0 +1,6 @@
char filesize\[20\];
char msgsize\[30\];
char fieldsize\[40\];
pb_callback_t int32_callback;
\sEnumValue1 = 1
Message5_EnumValue1

56
tests/options.proto Normal file
View File

@@ -0,0 +1,56 @@
/* Test nanopb option parsing.
* options.expected lists the patterns that are searched for in the output.
*/
import "nanopb.proto";
// File level options
option (nanopb_fileopt).max_size = 20;
message Message1
{
required string filesize = 1;
}
// Message level options
message Message2
{
option (nanopb_msgopt).max_size = 30;
required string msgsize = 1;
}
// Field level options
message Message3
{
required string fieldsize = 1 [(nanopb).max_size = 40];
}
// Forced callback field
message Message4
{
required int32 int32_callback = 1 [(nanopb).type = FT_CALLBACK];
}
// Short enum names
enum Enum1
{
option (nanopb_enumopt).long_names = false;
EnumValue1 = 1;
EnumValue2 = 2;
}
message EnumTest
{
required Enum1 field = 1 [default = EnumValue2];
}
// Short enum names inside message
message Message5
{
enum Enum2
{
option (nanopb_enumopt).long_names = false;
EnumValue1 = 1;
}
required Enum2 field = 1 [default = EnumValue1];
}

Binary file not shown.

View File

@@ -63,6 +63,12 @@ int main()
uint8_t buffer[512];
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
if (!feof(stdin))
{
printf("Message does not fit in buffer\n");
return 1;
}
/* Construct a pb_istream_t for reading from the buffer */
pb_istream_t stream = pb_istream_from_buffer(buffer, count);

View File

@@ -59,13 +59,6 @@ bool callback(pb_istream_t *stream, uint8_t *buf, size_t count)
FILE *file = (FILE*)stream->state;
bool status;
if (buf == NULL)
{
/* Skipping data */
while (count-- && fgetc(file) != EOF);
return count == 0;
}
status = (fread(buf, 1, count, file) == count);
if (feof(file))

View File

@@ -26,20 +26,20 @@ bool check_alltypes(pb_istream_t *stream, int mode)
if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false;
TEST(alltypes.req_int32 == 1001);
TEST(alltypes.req_int64 == 1002);
TEST(alltypes.req_int32 == -1001);
TEST(alltypes.req_int64 == -1002);
TEST(alltypes.req_uint32 == 1003);
TEST(alltypes.req_uint64 == 1004);
TEST(alltypes.req_sint32 == 1005);
TEST(alltypes.req_sint64 == 1006);
TEST(alltypes.req_sint32 == -1005);
TEST(alltypes.req_sint64 == -1006);
TEST(alltypes.req_bool == true);
TEST(alltypes.req_fixed32 == 1008);
TEST(alltypes.req_sfixed32 == 1009);
TEST(alltypes.req_sfixed32 == -1009);
TEST(alltypes.req_float == 1010.0f);
TEST(alltypes.req_fixed64 == 1011);
TEST(alltypes.req_sfixed64 == 1012);
TEST(alltypes.req_sfixed64 == -1012);
TEST(alltypes.req_double == 1013.0f);
TEST(strcmp(alltypes.req_string, "1014") == 0);
@@ -50,20 +50,20 @@ bool check_alltypes(pb_istream_t *stream, int mode)
TEST(alltypes.req_submsg.substuff3 == 3);
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_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_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_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_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');

View File

@@ -14,20 +14,20 @@ int main(int argc, char **argv)
/* Initialize the structure with constants */
AllTypes alltypes = {0};
alltypes.req_int32 = 1001;
alltypes.req_int64 = 1002;
alltypes.req_int32 = -1001;
alltypes.req_int64 = -1002;
alltypes.req_uint32 = 1003;
alltypes.req_uint64 = 1004;
alltypes.req_sint32 = 1005;
alltypes.req_sint64 = 1006;
alltypes.req_sint32 = -1005;
alltypes.req_sint64 = -1006;
alltypes.req_bool = true;
alltypes.req_fixed32 = 1008;
alltypes.req_sfixed32 = 1009;
alltypes.req_sfixed32 = -1009;
alltypes.req_float = 1010.0f;
alltypes.req_fixed64 = 1011;
alltypes.req_sfixed64 = 1012;
alltypes.req_sfixed64 = -1012;
alltypes.req_double = 1013.0;
strcpy(alltypes.req_string, "1014");
@@ -37,20 +37,20 @@ int main(int argc, char **argv)
alltypes.req_submsg.substuff2 = 1016;
alltypes.req_enum = MyEnum_Truth;
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = 2001;
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = 2002;
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = 2005;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = 2006;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = 2009;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009;
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = 2012;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = -2012;
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");

View File

@@ -0,0 +1,13 @@
/*
* Tests if still compile if typedefs are redfefined in STATIC_ASSERTS when
* proto file includes another poto file
*/
#include <stdio.h>
#include <pb_encode.h>
#include "callbacks2.pb.h"
int main()
{
return 0;
}

10
tools/set_version.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Run this from the top directory of nanopb tree.
# e.g. user@localhost:~/nanopb$ tools/set_version.sh nanopb-0.1.9-dev
# It sets the version number in pb.h and generator/nanopb_generator.py.
sed -i -e 's/nanopb_version\s*=\s*"[^"]*"/nanopb_version = "'$1'"/' generator/nanopb_generator.py
sed -i -e 's/#define\s*NANOPB_VERSION\s*.*/#define NANOPB_VERSION '$1'/' pb.h