Fix handling of unsigned 8- or 16-bit enums.
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>
Sat, 12 Sep 2015 10:04:22 +0000 (13:04 +0300)
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>
Sat, 12 Sep 2015 10:07:34 +0000 (13:07 +0300)
Previously unsigned enums would throw errors on decoding if the value
went outside the signed range (issue #164).

Currently only helps for enums defined within the same file, but solving
issue #165 will make it work for multiple files also.

generator/nanopb_generator.py
pb.h

index aaa0d2f..2b1d63e 100755 (executable)
@@ -162,6 +162,12 @@ class Enum:
         self.value_longnames = [self.names + x.name for x in desc.value]
         self.packed = enum_options.packed_enum
     
+    def has_negative(self):
+        for n, v in self.values:
+            if v < 0:
+                return True
+        return False
+    
     def __str__(self):
         result = 'typedef enum _%s {\n' % self.names
         result += ',\n'.join(["    %s = %d" % x for x in self.values])
@@ -342,7 +348,7 @@ class Field:
                 inner_init = '""'
             elif self.pbtype == 'BYTES':
                 inner_init = '{0, {0}}'
-            elif self.pbtype == 'ENUM':
+            elif self.pbtype in ('ENUM', 'UENUM'):
                 inner_init = '(%s)0' % self.ctype
             else:
                 inner_init = '0'
@@ -600,6 +606,7 @@ class OneOf(Field):
         self.struct_name = struct_name
         self.name = oneof_desc.name
         self.ctype = 'union'
+        self.pbtype = 'oneof'
         self.fields = []
         self.allocation = 'ONEOF'
         self.default = None
@@ -891,6 +898,14 @@ def parse_file(fdesc, file_options):
                         idx = enum.value_longnames.index(field.default)
                         field.default = enum.values[idx][0]
     
+    # Fix field data types where enums have negative values.
+    for enum in enums:
+        if not enum.has_negative():
+            for message in messages:
+                for field in message.fields:
+                    if field.pbtype == 'ENUM' and field.ctype == enum.names:
+                        field.pbtype = 'UENUM'
+    
     return enums, messages, extensions
 
 def toposort2(data):
diff --git a/pb.h b/pb.h
index 649a25e..ef2a166 100644 (file)
--- a/pb.h
+++ b/pb.h
@@ -468,6 +468,7 @@ struct pb_extension_s {
 #define PB_LTYPE_MAP_BYTES      PB_LTYPE_BYTES
 #define PB_LTYPE_MAP_DOUBLE     PB_LTYPE_FIXED64
 #define PB_LTYPE_MAP_ENUM       PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_UENUM      PB_LTYPE_UVARINT
 #define PB_LTYPE_MAP_FIXED32    PB_LTYPE_FIXED32
 #define PB_LTYPE_MAP_FIXED64    PB_LTYPE_FIXED64
 #define PB_LTYPE_MAP_FLOAT      PB_LTYPE_FIXED32
@@ -486,7 +487,7 @@ struct pb_extension_s {
 /* This is the actual macro used in field descriptions.
  * It takes these arguments:
  * - Field tag number
- * - Field type:   BOOL, BYTES, DOUBLE, ENUM, FIXED32, FIXED64,
+ * - Field type:   BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64,
  *                 FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
  *                 SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
  * - Field rules:  REQUIRED, OPTIONAL or REPEATED