-#!/usr/bin/python
+#!/usr/bin/env python
+
+from __future__ import unicode_literals
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
-nanopb_version = "nanopb-0.3.4-dev"
+nanopb_version = "nanopb-0.3.5-dev"
import sys
import re
return '_'.join(self.parts)
def __add__(self, other):
- if isinstance(other, str):
+ # The fdesc names are unicode and need to be handled for
+ # python2 and python3
+ try:
+ realstr = unicode
+ except NameError:
+ realstr = str
+
+ if isinstance(other, realstr):
return Names(self.parts + (other,))
elif isinstance(other, tuple):
return Names(self.parts + other)
return result
+class FieldMaxSize:
+ def __init__(self, worst = 0, checks = [], field_name = 'undefined'):
+ if isinstance(worst, list):
+ self.worst = max(i for i in worst if i is not None)
+ else:
+ self.worst = worst
+
+ self.worst_field = field_name
+ self.checks = checks
+
+ def extend(self, extend, field_name = None):
+ self.worst = max(self.worst, extend.worst)
+
+ if self.worst == extend.worst:
+ self.worst_field = extend.worst_field
+
+ self.checks.extend(extend.checks)
+
class Field:
def __init__(self, struct_name, desc, field_options):
'''desc is FieldDescriptorProto'''
else:
raise NotImplementedError(desc.type)
- def __cmp__(self, other):
- return cmp(self.tag, other.tag)
+ def __lt__(self, other):
+ return self.tag < other.tag
def __str__(self):
result = ''
inner_init = '0'
else:
if self.pbtype == 'STRING':
- inner_init = self.default.encode('utf-8').encode('string_escape')
- inner_init = inner_init.replace('"', '\\"')
+ inner_init = self.default.replace('"', '\\"')
inner_init = '"' + inner_init + '"'
elif self.pbtype == 'BYTES':
- data = str(self.default).decode('string_escape')
- data = ['0x%02x' % ord(c) for c in data]
+ data = ['0x%02x' % ord(c) for c in self.default]
if len(data) == 0:
inner_init = '{0, {0}}'
else:
def largest_field_value(self):
'''Determine if this field needs 16bit or 32bit pb_field_t structure to compile properly.
Returns numeric value or a C-expression for assert.'''
+ check = []
if self.pbtype == 'MESSAGE':
if self.rules == 'REPEATED' and self.allocation == 'STATIC':
- return 'pb_membersize(%s, %s[0])' % (self.struct_name, self.name)
+ check.append('pb_membersize(%s, %s[0])' % (self.struct_name, self.name))
elif self.rules == 'ONEOF':
- return 'pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name)
+ check.append('pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name))
else:
- return 'pb_membersize(%s, %s)' % (self.struct_name, self.name)
+ check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name))
- return max(self.tag, self.max_size, self.max_count)
+ return FieldMaxSize([self.tag, self.max_size, self.max_count],
+ check,
+ ('%s.%s' % (self.struct_name, self.name)))
def encoded_size(self, dependencies):
'''Return the maximum size that this field can take when encoded,
# Sort by the lowest tag number inside union
self.tag = min([f.tag for f in self.fields])
- def __cmp__(self, other):
- return cmp(self.tag, other.tag)
-
def __str__(self):
result = ''
if self.fields:
return result
def largest_field_value(self):
- return max([f.largest_field_value() for f in self.fields])
+ largest = FieldMaxSize()
+ for f in self.fields:
+ largest.extend(f.largest_field_value())
+ return largest
def encoded_size(self, dependencies):
largest = EncodedSize(0)
yield '#error Properly detecting missing required fields in %s requires \\\n' % largest_msg.name
yield ' setting PB_MAX_REQUIRED_FIELDS to %d or more.\n' % largest_count
yield '#endif\n'
-
- worst = 0
- worst_field = ''
- checks = []
+
+ max_field = FieldMaxSize()
checks_msgnames = []
for msg in self.messages:
checks_msgnames.append(msg.name)
for field in msg.fields:
- status = field.largest_field_value()
- if isinstance(status, str):
- checks.append(status)
- elif status > worst:
- worst = status
- worst_field = str(field.struct_name) + '.' + str(field.name)
+ max_field.extend(field.largest_field_value())
+
+ worst = max_field.worst
+ worst_field = max_field.worst_field
+ checks = max_field.checks
if worst > 255 or checks:
yield '\n/* Check that field information fits in pb_field_t */\n'
def main_plugin():
'''Main function when invoked as a protoc plugin.'''
- import sys
+ import io, sys
if sys.platform == "win32":
import os, msvcrt
# Set stdin and stdout to binary mode
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
- data = sys.stdin.read()
+ data = io.open(sys.stdin.fileno(), "rb").read()
+
request = plugin_pb2.CodeGeneratorRequest.FromString(data)
try:
f.name = results['sourcename']
f.content = results['sourcedata']
- sys.stdout.write(response.SerializeToString())
+ io.open(sys.stdout.fileno(), "wb").write(response.SerializeToString())
if __name__ == '__main__':
# Check if we are running as a plugin under protoc