Compare commits

...

15 Commits

Author SHA1 Message Date
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
20 changed files with 478 additions and 142 deletions

View File

@@ -1,3 +1,13 @@
nanopb-0.1.7 (not yet released)
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 nanopb-0.1.6
Reorganize the field decoder interface (issue 2) Reorganize the field decoder interface (issue 2)
Improve performance in submessage decoding (issue 28) 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 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 Streams
======= =======
@@ -92,9 +106,8 @@ Writing to stdout::
Input streams 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. #) 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:: Here is the structure::

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 fd = (intptr_t)stream->state;
int result; 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); result = recv(fd, buf, count, MSG_WAITALL);
if (result == 0) if (result == 0)

View File

@@ -7,9 +7,24 @@
import "google/protobuf/descriptor.proto"; 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 { message NanoPBOptions {
// Allocated size for 'bytes' and 'string' fields.
optional int32 max_size = 1; optional int32 max_size = 1;
// Allocated number of entries in arrays ('repeated' fields)
optional int32 max_count = 2; 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 // Protocol Buffers extension number registry
@@ -20,7 +35,20 @@ message NanoPBOptions {
// Extensions: 1010 (all types) // 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 { extend google.protobuf.FieldOptions {
optional NanoPBOptions nanopb = 1010; optional NanoPBOptions nanopb = 1010;
} }

View File

@@ -1,4 +1,5 @@
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
nanopb_version = "nanopb-0.1.7"
try: try:
import google.protobuf.descriptor_pb2 as descriptor import google.protobuf.descriptor_pb2 as descriptor
@@ -22,6 +23,16 @@ except:
print print
raise raise
# ---------------------------------------------------------------------------
# Generation of single fields
# ---------------------------------------------------------------------------
import time
import os.path import os.path
# Values are tuple (c type, pb ltype) # Values are tuple (c type, pb ltype)
@@ -69,19 +80,24 @@ def names_from_type_name(type_name):
return Names(type_name[1:].split('.')) return Names(type_name[1:].split('.'))
class Enum: class Enum:
def __init__(self, names, desc): def __init__(self, names, desc, enum_options):
'''desc is EnumDescriptorProto''' '''desc is EnumDescriptorProto'''
self.names = names + desc.name
if enum_options.long_names:
self.names = names + desc.name
else:
self.names = names
self.values = [(self.names + x.name, x.number) for x in desc.value] self.values = [(self.names + x.name, x.number) for x in desc.value]
def __str__(self): 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'.join([" %s = %d" % x for x in self.values])
result += '\n} %s;' % self.names result += '\n} %s;' % self.names
return result return result
class Field: class Field:
def __init__(self, struct_name, desc): def __init__(self, struct_name, desc, field_options):
'''desc is FieldDescriptorProto''' '''desc is FieldDescriptorProto'''
self.tag = desc.number self.tag = desc.number
self.struct_name = struct_name self.struct_name = struct_name
@@ -91,28 +107,27 @@ class Field:
self.max_count = None self.max_count = None
self.array_decl = "" self.array_decl = ""
# Parse nanopb-specific field options # Parse field options
if desc.options.HasExtension(nanopb_pb2.nanopb): if field_options.HasField("max_size"):
ext = desc.options.Extensions[nanopb_pb2.nanopb] self.max_size = field_options.max_size
if ext.HasField("max_size"):
self.max_size = ext.max_size if field_options.HasField("max_count"):
if ext.HasField("max_count"): self.max_count = field_options.max_count
self.max_count = ext.max_count
if desc.HasField('default_value'): if desc.HasField('default_value'):
self.default = desc.default_value self.default = desc.default_value
# Decide HTYPE # Decide HTYPE
# HTYPE is the high-order nibble of nanopb field description, # HTYPE is the high-order nibble of nanopb field description,
# defining whether value is required/optional/repeated. # defining whether value is required/optional/repeated.
is_callback = False can_be_static = True
if desc.label == FieldD.LABEL_REQUIRED: if desc.label == FieldD.LABEL_REQUIRED:
self.htype = 'PB_HTYPE_REQUIRED' self.htype = 'PB_HTYPE_REQUIRED'
elif desc.label == FieldD.LABEL_OPTIONAL: elif desc.label == FieldD.LABEL_OPTIONAL:
self.htype = 'PB_HTYPE_OPTIONAL' self.htype = 'PB_HTYPE_OPTIONAL'
elif desc.label == FieldD.LABEL_REPEATED: elif desc.label == FieldD.LABEL_REPEATED:
if self.max_count is None: if self.max_count is None:
is_callback = True can_be_static = False
else: else:
self.htype = 'PB_HTYPE_ARRAY' self.htype = 'PB_HTYPE_ARRAY'
self.array_decl = '[%d]' % self.max_count self.array_decl = '[%d]' % self.max_count
@@ -133,14 +148,14 @@ class Field:
elif desc.type == FieldD.TYPE_STRING: elif desc.type == FieldD.TYPE_STRING:
self.ltype = 'PB_LTYPE_STRING' self.ltype = 'PB_LTYPE_STRING'
if self.max_size is None: if self.max_size is None:
is_callback = True can_be_static = False
else: else:
self.ctype = 'char' self.ctype = 'char'
self.array_decl += '[%d]' % self.max_size self.array_decl += '[%d]' % self.max_size
elif desc.type == FieldD.TYPE_BYTES: elif desc.type == FieldD.TYPE_BYTES:
self.ltype = 'PB_LTYPE_BYTES' self.ltype = 'PB_LTYPE_BYTES'
if self.max_size is None: if self.max_size is None:
is_callback = True can_be_static = False
else: else:
self.ctype = self.struct_name + self.name + 't' self.ctype = self.struct_name + self.name + 't'
elif desc.type == FieldD.TYPE_MESSAGE: elif desc.type == FieldD.TYPE_MESSAGE:
@@ -149,7 +164,16 @@ class Field:
else: else:
raise NotImplementedError(desc.type) 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.htype = 'PB_HTYPE_CALLBACK'
self.ctype = 'pb_callback_t' self.ctype = 'pb_callback_t'
self.array_decl = '' self.array_decl = ''
@@ -264,10 +288,19 @@ class Field:
return max(self.tag, self.max_size, self.max_count) return max(self.tag, self.max_size, self.max_count)
# ---------------------------------------------------------------------------
# Generation of messages (structures)
# ---------------------------------------------------------------------------
class Message: class Message:
def __init__(self, names, desc): def __init__(self, names, desc, message_options):
self.name = names 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 = self.fields[:]
self.ordered_fields.sort() self.ordered_fields.sort()
@@ -276,7 +309,7 @@ class Message:
return [str(field.ctype) for field in self.fields] return [str(field.ctype) for field in self.fields]
def __str__(self): 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'.join([str(f) for f in self.ordered_fields])
result += '\n} %s;' % self.name result += '\n} %s;' % self.name
return result return result
@@ -313,6 +346,16 @@ class Message:
result += ' PB_LAST_FIELD\n};' result += ' PB_LAST_FIELD\n};'
return result return result
# ---------------------------------------------------------------------------
# Processing of entire .proto files
# ---------------------------------------------------------------------------
def iterate_messages(desc, names = Names()): def iterate_messages(desc, names = Names()):
'''Recursively find all messages. For each, yield name, DescriptorProto.''' '''Recursively find all messages. For each, yield name, DescriptorProto.'''
if hasattr(desc, 'message_type'): if hasattr(desc, 'message_type'):
@@ -327,7 +370,7 @@ def iterate_messages(desc, names = Names()):
for x in iterate_messages(submsg, sub_names): for x in iterate_messages(submsg, sub_names):
yield x yield x
def parse_file(fdesc): def parse_file(fdesc, file_options):
'''Takes a FileDescriptorProto and returns tuple (enum, messages).''' '''Takes a FileDescriptorProto and returns tuple (enum, messages).'''
enums = [] enums = []
@@ -339,12 +382,14 @@ def parse_file(fdesc):
base_name = Names() base_name = Names()
for enum in fdesc.enum_type: 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): 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: for enum in message.enum_type:
enums.append(Enum(names, enum)) enums.append(Enum(names, enum, message_options))
return enums, messages return enums, messages
@@ -385,6 +430,7 @@ def generate_header(dependencies, headername, enums, messages):
''' '''
yield '/* Automatically generated nanopb header */\n' yield '/* Automatically generated nanopb header */\n'
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
symbol = headername.replace('.', '_').upper() symbol = headername.replace('.', '_').upper()
yield '#ifndef _PB_%s_\n' % symbol yield '#ifndef _PB_%s_\n' % symbol
@@ -394,7 +440,10 @@ def generate_header(dependencies, headername, enums, messages):
for dependency in dependencies: for dependency in dependencies:
noext = os.path.splitext(dependency)[0] noext = os.path.splitext(dependency)[0]
yield '#include "%s.pb.h"\n' % noext 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' yield '/* Enum definitions */\n'
for enum in enums: for enum in enums:
@@ -458,6 +507,10 @@ def generate_header(dependencies, headername, enums, messages):
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT)\n' % assertion yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT)\n' % assertion
yield '#endif\n' yield '#endif\n'
yield '\n#ifdef __cplusplus\n'
yield '} /* extern "C" */\n'
yield '#endif\n'
# End of header # End of header
yield '\n#endif\n' yield '\n#endif\n'
@@ -465,6 +518,7 @@ def generate_source(headername, enums, messages):
'''Generate content for a source file.''' '''Generate content for a source file.'''
yield '/* Automatically generated nanopb constant definitions */\n' yield '/* Automatically generated nanopb constant definitions */\n'
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
yield '#include "%s"\n\n' % headername yield '#include "%s"\n\n' % headername
for msg in messages: for msg in messages:
@@ -475,39 +529,105 @@ def generate_source(headername, enums, messages):
for msg in messages: for msg in messages:
yield msg.fields_definition() + '\n\n' 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: if isinstance(subdesc.options, descriptor.FieldOptions):
print "Usage: " + sys.argv[0] + " file.pb" ext_type = nanopb_pb2.nanopb
print "where file.pb has been compiled from .proto by:" elif isinstance(subdesc.options, descriptor.FileOptions):
print "protoc -ofile.pb file.proto" ext_type = nanopb_pb2.nanopb_fileopt
print "Output fill be written to file.pb.h and file.pb.c" 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) 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) # @@protoc_insertion_point(imports)
import google.protobuf.descriptor_pb2
DESCRIPTOR = descriptor.FileDescriptor( DESCRIPTOR = descriptor.FileDescriptor(
name='nanopb.proto', name='nanopb.proto',
package='', 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_FIELD_NUMBER = 1010
nanopb = descriptor.FieldDescriptor( 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, number=1010, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None, has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=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, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
options=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=[ extensions=[
], ],
@@ -54,11 +123,11 @@ _NANOPBOPTIONS = descriptor.Descriptor(
is_extendable=False, is_extendable=False,
extension_ranges=[], extension_ranges=[],
serialized_start=50, 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): class NanoPBOptions(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType __metaclass__ = reflection.GeneratedProtocolMessageType
@@ -66,6 +135,12 @@ class NanoPBOptions(message.Message):
# @@protoc_insertion_point(class_scope:NanoPBOptions) # @@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 nanopb.message_type = _NANOPBOPTIONS
google.protobuf.descriptor_pb2.FieldOptions.RegisterExtension(nanopb) google.protobuf.descriptor_pb2.FieldOptions.RegisterExtension(nanopb)
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

17
pb.h
View File

@@ -6,6 +6,8 @@
* see pb_encode.h or pb_decode.h * see pb_encode.h or pb_decode.h
*/ */
#define NANOPB_VERSION nanopb-0.1.7
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
@@ -75,6 +77,7 @@ typedef enum {
/* Number of declared LTYPES */ /* Number of declared LTYPES */
PB_LTYPES_COUNT = 7, PB_LTYPES_COUNT = 7,
PB_LTYPE_MASK = 0x0F,
/****************** /******************
* Modifier flags * * Modifier flags *
@@ -95,11 +98,13 @@ typedef enum {
* data_offset points to pb_callback_t structure. * data_offset points to pb_callback_t structure.
* LTYPE should be 0 (it is ignored, but sometimes * LTYPE should be 0 (it is ignored, but sometimes
* used to speculatively index an array). */ * used to speculatively index an array). */
PB_HTYPE_CALLBACK = 0x30 PB_HTYPE_CALLBACK = 0x30,
PB_HTYPE_MASK = 0xF0
} pb_packed pb_type_t; } pb_packed pb_type_t;
#define PB_HTYPE(x) ((x) & 0xF0) #define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & 0x0F) #define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
/* This structure is used in auto-generated constants /* This structure is used in auto-generated constants
* to specify struct fields. * to specify struct fields.
@@ -145,10 +150,12 @@ struct _pb_field_t {
* It has the number of bytes in the beginning, and after that an array. * It has the number of bytes in the beginning, and after that an array.
* Note that actual structs used will have a different length of bytes array. * Note that actual structs used will have a different length of bytes array.
*/ */
typedef struct { struct _pb_bytes_array_t {
size_t size; size_t size;
uint8_t bytes[1]; 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. /* 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

View File

@@ -36,18 +36,6 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
* pb_istream * * 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) static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{ {
uint8_t *source = (uint8_t*)stream->state; uint8_t *source = (uint8_t*)stream->state;
@@ -59,6 +47,33 @@ static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t coun
return true; 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 pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
{ {
pb_istream_t stream; pb_istream_t stream;
@@ -83,7 +98,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) bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
{ {
uint8_t byte; uint8_t byte;
uint8_t bitpos = 0; int bitpos = 0;
*dest = 0; *dest = 0;
while (bitpos < 64 && pb_read(stream, &byte, 1)) while (bitpos < 64 && pb_read(stream, &byte, 1))
@@ -447,7 +462,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS) && 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)) if (!decode_field(stream, wire_type, &iter))
@@ -483,9 +498,9 @@ bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest)
return false; return false;
if (value & 1) if (value & 1)
*dest = ~(value >> 1); *dest = (int64_t)(~(value >> 1));
else else
*dest = value >> 1; *dest = (int64_t)(value >> 1);
return true; return true;
} }
@@ -539,9 +554,9 @@ 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 = value; break; case 1: *(uint8_t*)dest = (uint8_t)value; break;
case 2: *(uint16_t*)dest = value; break; case 2: *(uint16_t*)dest = (uint16_t)value; break;
case 4: *(uint32_t*)dest = 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");
} }
@@ -556,7 +571,7 @@ bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, v
switch (field->data_size) 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; case 8: *(int64_t*)dest = value; break;
default: PB_RETURN_ERROR(stream, "invalid data_size"); default: PB_RETURN_ERROR(stream, "invalid data_size");
} }

View File

@@ -12,6 +12,10 @@
#include <stdbool.h> #include <stdbool.h>
#include "pb.h" #include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Lightweight input stream. /* Lightweight input stream.
* You can provide a callback function for reading or use * You can provide a callback function for reading or use
* pb_istream_from_buffer. * pb_istream_from_buffer.
@@ -19,12 +23,10 @@
* Rules for callback: * Rules for callback:
* 1) Return false on IO errors. This will cause decoding to abort. * 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"). * 2) You can use state to store your own data (e.g. buffer pointer),
*
* 3) 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. * 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 * is different than from the main stream. Don't use bytes_left to compute
* any pointers. * any pointers.
*/ */
@@ -104,4 +106,8 @@ bool pb_skip_varint(pb_istream_t *stream);
bool pb_skip_string(pb_istream_t *stream); bool pb_skip_string(pb_istream_t *stream);
#endif #endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#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) bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
{ {
uint8_t buffer[10]; uint8_t buffer[10];
int i = 0; size_t i = 0;
if (value == 0) if (value == 0)
return pb_write(stream, (uint8_t*)&value, 1); 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; uint64_t zigzagged;
if (value < 0) if (value < 0)
zigzagged = ~(value << 1); zigzagged = (uint64_t)(~(value << 1));
else else
zigzagged = value << 1; zigzagged = (uint64_t)(value << 1);
return pb_encode_varint(stream, zigzagged); return pb_encode_varint(stream, zigzagged);
} }
@@ -266,7 +266,7 @@ bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
#endif #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); uint64_t tag = wiretype | (field_number << 3);
return pb_encode_varint(stream, tag); 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) 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) switch (field->data_size)
{ {

View File

@@ -9,6 +9,10 @@
#include <stdbool.h> #include <stdbool.h>
#include "pb.h" #include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Lightweight output stream. /* Lightweight output stream.
* You can provide callback for writing or use pb_ostream_from_buffer. * 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 /* 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. */ * 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. /* Encode an integer in the varint format.
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */ * 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. */ * 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); bool pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif #endif

View File

@@ -4,7 +4,7 @@ DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h callbacks.pb.h unittests.
TESTS=test_decode1 test_encode1 decode_unittests encode_unittests test_no_messages TESTS=test_decode1 test_encode1 decode_unittests encode_unittests test_no_messages
# More strict checks for the core part of nanopb # More strict checks for the core part of nanopb
CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wlogical-op CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wlogical-op -Wconversion
all: breakpoints $(TESTS) run_unittests all: breakpoints $(TESTS) run_unittests
@@ -55,7 +55,7 @@ coverage: run_unittests
gcov pb_encode.gcda gcov pb_encode.gcda
gcov pb_decode.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: 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 test_options
rm -f *.gcda rm -f *.gcda
./decode_unittests > /dev/null ./decode_unittests > /dev/null
@@ -70,6 +70,9 @@ run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 te
[ "`./test_encode2 | ./test_decode2`" = \ [ "`./test_encode2 | ./test_decode2`" = \
"`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ] "`./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 | ./test_decode_callbacks`" = \
"`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ] "`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ]
@@ -79,5 +82,13 @@ run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 te
./test_missing_fields ./test_missing_fields
test_options: options.pb.h options.expected
cat options.expected | while read -r p; do \
if ! grep -q "$$p" $<; then \
echo Expected: "$$p"; \
exit 1; \
fi \
done
run_fuzztest: test_decode2 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' bash -c 'I=1; while true; do cat /dev/urandom | ./test_decode2 > /dev/null; I=$$(($$I+1)); echo -en "\r$$I"; done'

5
tests/options.expected Normal file
View File

@@ -0,0 +1,5 @@
char filesize\[20\];
char msgsize\[30\];
char fieldsize\[40\];
pb_callback_t int32_callback;
[^_]EnumValue1 = 1

39
tests/options.proto Normal file
View File

@@ -0,0 +1,39 @@
/* 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;
}

Binary file not shown.

View File

@@ -63,6 +63,12 @@ int main()
uint8_t buffer[512]; uint8_t buffer[512];
size_t count = fread(buffer, 1, sizeof(buffer), stdin); 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 */ /* Construct a pb_istream_t for reading from the buffer */
pb_istream_t stream = pb_istream_from_buffer(buffer, count); 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; FILE *file = (FILE*)stream->state;
bool status; bool status;
if (buf == NULL)
{
/* Skipping data */
while (count-- && fgetc(file) != EOF);
return count == 0;
}
status = (fread(buf, 1, count, file) == count); status = (fread(buf, 1, count, file) == count);
if (feof(file)) 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)) if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false; return false;
TEST(alltypes.req_int32 == 1001); TEST(alltypes.req_int32 == -1001);
TEST(alltypes.req_int64 == 1002); TEST(alltypes.req_int64 == -1002);
TEST(alltypes.req_uint32 == 1003); TEST(alltypes.req_uint32 == 1003);
TEST(alltypes.req_uint64 == 1004); TEST(alltypes.req_uint64 == 1004);
TEST(alltypes.req_sint32 == 1005); TEST(alltypes.req_sint32 == -1005);
TEST(alltypes.req_sint64 == 1006); TEST(alltypes.req_sint64 == -1006);
TEST(alltypes.req_bool == true); TEST(alltypes.req_bool == true);
TEST(alltypes.req_fixed32 == 1008); TEST(alltypes.req_fixed32 == 1008);
TEST(alltypes.req_sfixed32 == 1009); TEST(alltypes.req_sfixed32 == -1009);
TEST(alltypes.req_float == 1010.0f); TEST(alltypes.req_float == 1010.0f);
TEST(alltypes.req_fixed64 == 1011); TEST(alltypes.req_fixed64 == 1011);
TEST(alltypes.req_sfixed64 == 1012); TEST(alltypes.req_sfixed64 == -1012);
TEST(alltypes.req_double == 1013.0f); TEST(alltypes.req_double == 1013.0f);
TEST(strcmp(alltypes.req_string, "1014") == 0); 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_submsg.substuff3 == 3);
TEST(alltypes.req_enum == MyEnum_Truth); 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_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_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_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_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_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_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_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_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_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_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_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0'); TEST(alltypes.rep_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 */ /* Initialize the structure with constants */
AllTypes alltypes = {0}; AllTypes alltypes = {0};
alltypes.req_int32 = 1001; alltypes.req_int32 = -1001;
alltypes.req_int64 = 1002; alltypes.req_int64 = -1002;
alltypes.req_uint32 = 1003; alltypes.req_uint32 = 1003;
alltypes.req_uint64 = 1004; alltypes.req_uint64 = 1004;
alltypes.req_sint32 = 1005; alltypes.req_sint32 = -1005;
alltypes.req_sint64 = 1006; alltypes.req_sint64 = -1006;
alltypes.req_bool = true; alltypes.req_bool = true;
alltypes.req_fixed32 = 1008; alltypes.req_fixed32 = 1008;
alltypes.req_sfixed32 = 1009; alltypes.req_sfixed32 = -1009;
alltypes.req_float = 1010.0f; alltypes.req_float = 1010.0f;
alltypes.req_fixed64 = 1011; alltypes.req_fixed64 = 1011;
alltypes.req_sfixed64 = 1012; alltypes.req_sfixed64 = -1012;
alltypes.req_double = 1013.0; alltypes.req_double = 1013.0;
strcpy(alltypes.req_string, "1014"); strcpy(alltypes.req_string, "1014");
@@ -37,20 +37,20 @@ int main(int argc, char **argv)
alltypes.req_submsg.substuff2 = 1016; alltypes.req_submsg.substuff2 = 1016;
alltypes.req_enum = MyEnum_Truth; alltypes.req_enum = MyEnum_Truth;
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = 2001; alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = 2002; alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003; alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004; alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = 2005; alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = 2006; alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true; alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008; 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_float_count = 5; alltypes.rep_float[4] = 2010.0f;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011; 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_double_count = 5; alltypes.rep_double[4] = 2013.0;
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014"); alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");

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