Bläddra i källkod

Update to v0.4.0

Wu Han 6 år sedan
förälder
incheckning
7b263ba0eb
7 ändrade filer med 1652 tillägg och 772 borttagningar
  1. 440 178
      pb.h
  2. 226 60
      pb_common.c
  3. 4 12
      pb_common.h
  4. 434 233
      pb_decode.c
  5. 55 19
      pb_decode.h
  6. 457 259
      pb_encode.c
  7. 36 11
      pb_encode.h

+ 440 - 178
pb.h

@@ -13,16 +13,13 @@
 /* Enable support for dynamically allocated fields */
 /* Enable support for dynamically allocated fields */
 /* #define PB_ENABLE_MALLOC 1 */
 /* #define PB_ENABLE_MALLOC 1 */
 
 
-/* Define this if your CPU architecture is big endian, i.e. it
- * stores the most-significant byte first. */
-/* #define __BIG_ENDIAN__ 1 */
+/* Define this if your CPU / compiler combination does not support
+ * unaligned memory access to packed structures. */
+/* #define PB_NO_PACKED_STRUCTS 1 */
 
 
 /* Increase the number of required fields that are tracked.
 /* Increase the number of required fields that are tracked.
  * A compiler warning will tell if you need this. */
  * A compiler warning will tell if you need this. */
-#define PB_MAX_REQUIRED_FIELDS 256
-
-/* Add support for tag numbers > 255 and fields larger than 255 bytes. */
-#define PB_FIELD_16BIT 1
+/* #define PB_MAX_REQUIRED_FIELDS 256 */
 
 
 /* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
 /* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
 /* #define PB_FIELD_32BIT 1 */
 /* #define PB_FIELD_32BIT 1 */
@@ -37,6 +34,11 @@
  * This was the default until nanopb-0.2.1. */
  * This was the default until nanopb-0.2.1. */
 /* #define PB_OLD_CALLBACK_STYLE */
 /* #define PB_OLD_CALLBACK_STYLE */
 
 
+/* Set the fieldinfo width for all messages using automatic width
+ * selection. Valid values are 2, 4 and 8. Usually even if you need
+ * to change the width manually for some reason, it is preferrable
+ * to do so through the descriptorsize option in .options file. */
+/* #define PB_FIELDINFO_WIDTH 4 */
 
 
 /******************************************************************
 /******************************************************************
  * You usually don't need to change anything below this line.     *
  * You usually don't need to change anything below this line.     *
@@ -46,12 +48,12 @@
 
 
 /* Version of the nanopb library. Just in case you want to check it in
 /* Version of the nanopb library. Just in case you want to check it in
  * your own program. */
  * your own program. */
-#define NANOPB_VERSION nanopb-0.3.1
+#define NANOPB_VERSION nanopb-0.4.0-dev
 
 
 /* Include all the system headers needed by nanopb. You will need the
 /* Include all the system headers needed by nanopb. You will need the
  * definitions of the following:
  * definitions of the following:
  * - strlen, memcpy, memset functions
  * - strlen, memcpy, memset functions
- * - [u]int8_t, [u]int16_t, [u]int32_t, [u]int64_t
+ * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t
  * - size_t
  * - size_t
  * - bool
  * - bool
  *
  *
@@ -66,16 +68,26 @@
 #include <stddef.h>
 #include <stddef.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <string.h>
 #include <string.h>
+#include <limits.h>
 
 
 #ifdef PB_ENABLE_MALLOC
 #ifdef PB_ENABLE_MALLOC
 #include <stdlib.h>
 #include <stdlib.h>
 #endif
 #endif
 #endif
 #endif
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Macro for defining packed structures (compiler dependent).
 /* Macro for defining packed structures (compiler dependent).
  * This just reduces memory requirements, but is not required.
  * This just reduces memory requirements, but is not required.
  */
  */
-#if defined(__GNUC__) || defined(__clang__)
+#if defined(PB_NO_PACKED_STRUCTS)
+    /* Disable struct packing */
+#   define PB_PACKED_STRUCT_START
+#   define PB_PACKED_STRUCT_END
+#   define pb_packed
+#elif defined(__GNUC__) || defined(__clang__)
     /* For GCC and clang */
     /* For GCC and clang */
 #   define PB_PACKED_STRUCT_START
 #   define PB_PACKED_STRUCT_START
 #   define PB_PACKED_STRUCT_END
 #   define PB_PACKED_STRUCT_END
@@ -112,13 +124,20 @@
  * in the place where the PB_STATIC_ASSERT macro was called.
  * in the place where the PB_STATIC_ASSERT macro was called.
  */
  */
 #ifndef PB_NO_STATIC_ASSERT
 #ifndef PB_NO_STATIC_ASSERT
-#ifndef PB_STATIC_ASSERT
-#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
-#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
-#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER
-#endif
+#  ifndef PB_STATIC_ASSERT
+#    if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+       /* C11 standard _Static_assert mechanism */
+#      define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
+#    else
+       /* Classic negative-size-array static assert mechanism */
+#      define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
+#      define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
+#      define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER
+#    endif
+#  endif
 #else
 #else
-#define PB_STATIC_ASSERT(COND,MSG)
+   /* Static asserts disabled by PB_NO_STATIC_ASSERT */
+#  define PB_STATIC_ASSERT(COND,MSG)
 #endif
 #endif
 
 
 /* Number of required fields to keep track of. */
 /* Number of required fields to keep track of. */
@@ -135,7 +154,7 @@
  * Most-significant 4 bits specify repeated/required/packed etc.
  * Most-significant 4 bits specify repeated/required/packed etc.
  */
  */
 
 
-typedef uint8_t pb_type_t;
+typedef uint_least8_t pb_type_t;
 
 
 /**** Field data types ****/
 /**** Field data types ****/
 
 
@@ -165,15 +184,24 @@ typedef uint8_t pb_type_t;
  * The field contains a pointer to pb_extension_t */
  * The field contains a pointer to pb_extension_t */
 #define PB_LTYPE_EXTENSION 0x08
 #define PB_LTYPE_EXTENSION 0x08
 
 
+/* Byte array with inline, pre-allocated byffer.
+ * data_size is the length of the inline, allocated buffer.
+ * This differs from PB_LTYPE_BYTES by defining the element as
+ * pb_byte_t[data_size] rather than pb_bytes_array_t. */
+#define PB_LTYPE_FIXED_LENGTH_BYTES 0x09
+
 /* Number of declared LTYPES */
 /* Number of declared LTYPES */
-#define PB_LTYPES_COUNT 9
+#define PB_LTYPES_COUNT 0x0A
 #define PB_LTYPE_MASK 0x0F
 #define PB_LTYPE_MASK 0x0F
 
 
 /**** Field repetition rules ****/
 /**** Field repetition rules ****/
 
 
 #define PB_HTYPE_REQUIRED 0x00
 #define PB_HTYPE_REQUIRED 0x00
 #define PB_HTYPE_OPTIONAL 0x10
 #define PB_HTYPE_OPTIONAL 0x10
+#define PB_HTYPE_SINGULAR 0x10
 #define PB_HTYPE_REPEATED 0x20
 #define PB_HTYPE_REPEATED 0x20
+#define PB_HTYPE_FIXARRAY 0x20
+#define PB_HTYPE_ONEOF    0x30
 #define PB_HTYPE_MASK     0x30
 #define PB_HTYPE_MASK     0x30
 
 
 /**** Field allocation types ****/
 /**** Field allocation types ****/
@@ -191,69 +219,86 @@ typedef uint8_t pb_type_t;
  * and array counts.
  * and array counts.
  */
  */
 #if defined(PB_FIELD_32BIT)
 #if defined(PB_FIELD_32BIT)
-#define PB_SIZE_MAX ((uint32_t)-1)
     typedef uint32_t pb_size_t;
     typedef uint32_t pb_size_t;
     typedef int32_t pb_ssize_t;
     typedef int32_t pb_ssize_t;
-#elif defined(PB_FIELD_16BIT)
-#define PB_SIZE_MAX ((uint16_t)-1)
-    typedef uint16_t pb_size_t;
-    typedef int16_t pb_ssize_t;
 #else
 #else
-#define PB_SIZE_MAX ((uint8_t)-1)
-    typedef uint8_t pb_size_t;
-    typedef int8_t pb_ssize_t;
+    typedef uint_least16_t pb_size_t;
+    typedef int_least16_t pb_ssize_t;
 #endif
 #endif
+#define PB_SIZE_MAX ((pb_size_t)-1)
+
+/* Data type for storing encoded data and other byte streams.
+ * This typedef exists to support platforms where uint8_t does not exist.
+ * You can regard it as equivalent on uint8_t on other platforms.
+ */
+typedef uint_least8_t pb_byte_t;
+
+/* Forward declaration of struct types */
+typedef struct pb_istream_s pb_istream_t;
+typedef struct pb_ostream_s pb_ostream_t;
+typedef struct pb_field_iter_s pb_field_iter_t;
 
 
 /* This structure is used in auto-generated constants
 /* This structure is used in auto-generated constants
  * to specify struct fields.
  * to specify struct fields.
- * You can change field sizes if you need structures
- * larger than 256 bytes or field tags larger than 256.
- * The compiler should complain if your .proto has such
- * structures. Fix that by defining PB_FIELD_16BIT or
- * PB_FIELD_32BIT.
  */
  */
 PB_PACKED_STRUCT_START
 PB_PACKED_STRUCT_START
-typedef struct pb_field_s pb_field_t;
-struct pb_field_s {
-    pb_size_t tag;
-    pb_type_t type;
-    pb_size_t data_offset; /* Offset of field data, relative to previous field. */
-    pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */
-    pb_size_t data_size; /* Data size in bytes for a single item */
-    pb_size_t array_size; /* Maximum number of entries in array */
-    
-    /* Field definitions for submessage
-     * OR default value for all other non-array, non-callback types
-     * If null, then field will zeroed. */
-    const void *ptr;
+typedef struct pb_msgdesc_s pb_msgdesc_t;
+struct pb_msgdesc_s {
+    pb_size_t field_count;
+    const uint32_t *field_info;
+    const pb_msgdesc_t **submsg_info;
+    const pb_byte_t *default_value;
+
+    bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
 } pb_packed;
 } pb_packed;
 PB_PACKED_STRUCT_END
 PB_PACKED_STRUCT_END
 
 
+/* Iterator for message descriptor */
+struct pb_field_iter_s {
+    const pb_msgdesc_t *descriptor;  /* Pointer to message descriptor constant */
+    void *message;                   /* Pointer to start of the structure */
+
+    pb_size_t index;                 /* Index of the field */
+    pb_size_t field_info_index;      /* Index to descriptor->field_info array */
+    pb_size_t required_field_index;  /* Index that counts only the required fields */
+    pb_size_t submessage_index;      /* Index that counts only submessages */
+
+    pb_size_t tag;                   /* Tag of current field */
+    pb_size_t data_size;             /* sizeof() of a single item */
+    pb_size_t array_size;            /* Number of array entries */
+    pb_type_t type;                  /* Type of current field */
+
+    void *pField;                    /* Pointer to current field in struct */
+    void *pData;                     /* Pointer to current data contents. Different than pField for arrays and pointers. */
+    void *pSize;                     /* Pointer to count/has field */
+
+    const pb_msgdesc_t *submsg_desc; /* For submessage fields, pointer to field descriptor for the submessage. */
+};
+
+/* For compatibility with legacy code */
+typedef pb_field_iter_t pb_field_t;
+
 /* Make sure that the standard integer types are of the expected sizes.
 /* Make sure that the standard integer types are of the expected sizes.
- * All kinds of things may break otherwise.. atleast all fixed* types.
+ * Otherwise fixed32/fixed64 fields can break.
  *
  *
  * If you get errors here, it probably means that your stdint.h is not
  * If you get errors here, it probably means that your stdint.h is not
  * correct for your platform.
  * correct for your platform.
  */
  */
-PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE)
-PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
+#ifndef PB_WITHOUT_64BIT
+PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE)
+PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE)
+#endif
 
 
 /* This structure is used for 'bytes' arrays.
 /* This structure is used for 'bytes' arrays.
  * 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.
  */
  */
-#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; uint8_t bytes[n]; }
+#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; }
 #define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
 #define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
 
 
 struct pb_bytes_array_s {
 struct pb_bytes_array_s {
     pb_size_t size;
     pb_size_t size;
-    uint8_t bytes[1];
+    pb_byte_t bytes[1];
 };
 };
 typedef struct pb_bytes_array_s pb_bytes_array_t;
 typedef struct pb_bytes_array_s pb_bytes_array_t;
 
 
@@ -275,8 +320,6 @@ typedef struct pb_bytes_array_s pb_bytes_array_t;
  *
  *
  * The callback can be null if you want to skip a field.
  * The callback can be null if you want to skip a field.
  */
  */
-typedef struct pb_istream_s pb_istream_t;
-typedef struct pb_ostream_s pb_ostream_t;
 typedef struct pb_callback_s pb_callback_t;
 typedef struct pb_callback_s pb_callback_t;
 struct pb_callback_s {
 struct pb_callback_s {
 #ifdef PB_OLD_CALLBACK_STYLE
 #ifdef PB_OLD_CALLBACK_STYLE
@@ -297,6 +340,8 @@ struct pb_callback_s {
     void *arg;
     void *arg;
 };
 };
 
 
+extern bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field);
+
 /* Wire types. Library user needs these only in encoder callbacks. */
 /* Wire types. Library user needs these only in encoder callbacks. */
 typedef enum {
 typedef enum {
     PB_WT_VARINT = 0,
     PB_WT_VARINT = 0,
@@ -366,7 +411,7 @@ struct pb_extension_s {
 #endif
 #endif
 
 
 /* This is used to inform about need to regenerate .pb.h/.pb.c files. */
 /* This is used to inform about need to regenerate .pb.h/.pb.c files. */
-#define PB_PROTO_HEADER_VERSION 30
+#define PB_PROTO_HEADER_VERSION 40
 
 
 /* These macros are used to declare pb_field_t's in the constant array. */
 /* These macros are used to declare pb_field_t's in the constant array. */
 /* Size of a structure member, in bytes. */
 /* Size of a structure member, in bytes. */
@@ -375,144 +420,361 @@ struct pb_extension_s {
 #define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
 #define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
 /* Delta from start of one member to the start of another member. */
 /* Delta from start of one member to the start of another member. */
 #define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
 #define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
-/* Marks the end of the field list */
-#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0}
-
-/* Macros for filling in the data_offset field */
-/* data_offset for first field in a message */
-#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1))
-/* data_offset for subsequent fields */
-#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2))
-/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */
-#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \
-                                  ? PB_DATAOFFSET_FIRST(st, m1, m2) \
-                                  : PB_DATAOFFSET_OTHER(st, m1, m2))
-
-/* Required fields are the simplest. They just have delta (padding) from
- * previous field end, and the size of the field. Pointer is used for
- * submessages and default values.
+
+/* Force expansion of macro value */
+#define PB_EXPAND(x) x
+
+/* Binding of a message field set into a specific structure */
+#define PB_BIND(msgname, structname, width) \
+    const uint32_t structname ## _field_info[] = \
+    { \
+        msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
+        0 \
+    }; \
+    const pb_msgdesc_t* structname ## _submsg_info[] = \
+    { \
+        msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
+        NULL \
+    }; \
+    const pb_msgdesc_t structname ## _msg = \
+    { \
+       0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
+       structname ## _field_info, \
+       structname ## _submsg_info, \
+       msgname ## _DEFAULT, \
+       msgname ## _CALLBACK, \
+    }; \
+    msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
+
+#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
+
+#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO(1, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO(2, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO(4, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO(8, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_ASSERT(1, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_ASSERT(2, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_ASSERT(4, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_ASSERT(8, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_ASSERT_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \
+    PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag)
+
+#define PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ASSERT_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname))
+
+#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname)
+#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname)
+#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname)
+#define PB_DATA_OFFSET_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DATA_OFFSET_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DATA_OFFSET_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
+#define PB_DATA_OFFSET_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DATA_OFFSET_REPEATED(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DATA_OFFSET_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
+
+#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SIZE_OFFSET_ ## htype(structname, fieldname)
+#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SIZE_OFFSET_PTR_ ## htype(structname, fieldname)
+#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) 0
+#define PB_SIZE_OFFSET_REQUIRED(structname, fieldname) 0
+#define PB_SIZE_OFFSET_SINGULAR(structname, fieldname) 0
+#define PB_SIZE_OFFSET_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
+#define PB_SIZE_OFFSET_ONEOF2(structname, fullname, unionname) PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname)
+#define PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
+#define PB_SIZE_OFFSET_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
+#define PB_SIZE_OFFSET_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
+#define PB_SIZE_OFFSET_FIXARRAY(structname, fieldname) 0
+#define PB_SIZE_OFFSET_PTR_REQUIRED(structname, fieldname) 0
+#define PB_SIZE_OFFSET_PTR_SINGULAR(structname, fieldname) 0
+#define PB_SIZE_OFFSET_PTR_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname)
+#define PB_SIZE_OFFSET_PTR_OPTIONAL(structname, fieldname) 0
+#define PB_SIZE_OFFSET_PTR_REPEATED(structname, fieldname) PB_SIZE_OFFSET_REPEATED(structname, fieldname)
+#define PB_SIZE_OFFSET_PTR_FIXARRAY(structname, fieldname) 0
+
+#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_ARRAY_SIZE_ ## htype(structname, fieldname)
+#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) 1
+#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
+#define PB_ARRAY_SIZE_REQUIRED(structname, fieldname) 1
+#define PB_ARRAY_SIZE_SINGULAR(structname, fieldname) 1
+#define PB_ARRAY_SIZE_OPTIONAL(structname, fieldname) 1
+#define PB_ARRAY_SIZE_ONEOF(structname, fieldname) 1
+#define PB_ARRAY_SIZE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
+#define PB_ARRAY_SIZE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
+
+#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DATA_SIZE_ ## htype(structname, fieldname)
+#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DATA_SIZE_PTR_ ## htype(structname, fieldname)
+#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DATA_SIZE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DATA_SIZE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DATA_SIZE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DATA_SIZE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
+#define PB_DATA_SIZE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DATA_SIZE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DATA_SIZE_PTR_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DATA_SIZE_PTR_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DATA_SIZE_PTR_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DATA_SIZE_PTR_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
+#define PB_DATA_SIZE_PTR_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DATA_SIZE_PTR_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
+
+#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple)
+#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname
+#define PB_ONEOF_NAME_MEMBER(unionname,membername,fullname) membername
+#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname
+
+#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \
+    PB_SUBMSG_INFO_ ## htype(ltype, structname, fieldname)
+
+#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname))
+#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername)
+#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
+#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_BOOL(t)
+#define PB_SUBMSG_INFO_BYTES(t)
+#define PB_SUBMSG_INFO_DOUBLE(t)
+#define PB_SUBMSG_INFO_ENUM(t)
+#define PB_SUBMSG_INFO_UENUM(t)
+#define PB_SUBMSG_INFO_FIXED32(t)
+#define PB_SUBMSG_INFO_FIXED64(t)
+#define PB_SUBMSG_INFO_FLOAT(t)
+#define PB_SUBMSG_INFO_INT32(t)
+#define PB_SUBMSG_INFO_INT64(t)
+#define PB_SUBMSG_INFO_MESSAGE(t)  PB_SUBMSG_DESCRIPTOR(t)
+#define PB_SUBMSG_INFO_SFIXED32(t)
+#define PB_SUBMSG_INFO_SFIXED64(t)
+#define PB_SUBMSG_INFO_SINT32(t)
+#define PB_SUBMSG_INFO_SINT64(t)
+#define PB_SUBMSG_INFO_STRING(t)
+#define PB_SUBMSG_INFO_UINT32(t)
+#define PB_SUBMSG_INFO_UINT64(t)
+#define PB_SUBMSG_INFO_EXTENSION(t)
+#define PB_SUBMSG_INFO_FIXED_LENGTH_BYTES(t)
+#define PB_SUBMSG_DESCRIPTOR(t)    &(t ## _msg),
+
+/* The field descriptors use a variable width format, with width of either
+ * 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always
+ * encode the descriptor size, 6 lowest bits of field tag number, and 8 bits
+ * of the field type.
+ *
+ * Descriptor size is encoded as 0 = 1 word, 1 = 2 words, 2 = 4 words, 3 = 8 words.
+ *
+ * Formats, listed starting with the least significant bit of the first word.
+ * 1 word:  [2-bit len] [6-bit tag] [8-bit type] [8-bit data_offset] [4-bit size_offset] [4-bit data_size]
+ *
+ * 2 words: [2-bit len] [6-bit tag] [8-bit type] [12-bit array_size] [4-bit size_offset]
+ *          [16-bit data_offset] [12-bit data_size] [4-bit tag>>6]
+ *
+ * 4 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit array_size]
+ *          [8-bit size_offset] [24-bit tag>>6]
+ *          [32-bit data_offset]
+ *          [32-bit data_size]
+ *
+ * 8 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit reserved]
+ *          [8-bit size_offset] [24-bit tag>>6]
+ *          [32-bit data_offset]
+ *          [32-bit data_size]
+ *          [32-bit array_size]
+ *          [32-bit reserved]
+ *          [32-bit reserved]
+ *          [32-bit reserved]
  */
  */
-#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-
-/* Optional fields add the delta to the has_ variable. */
-#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
-    fd, \
-    pb_delta(st, has_ ## m, m), \
-    pb_membersize(st, m), 0, ptr}
-
-/* Repeated fields have a _count field and also the maximum number of entries. */
-#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \
-    fd, \
-    pb_delta(st, m ## _count, m), \
-    pb_membersize(st, m[0]), \
-    pb_arraysize(st, m), ptr}
-
-/* Allocated fields carry the size of the actual data, not the pointer */
-#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
-    fd, 0, pb_membersize(st, m[0]), 0, ptr}
-
-/* Optional fields don't need a has_ variable, as information would be redundant */
-#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m[0]), 0, ptr}
-
-/* Repeated fields have a _count field and a pointer to array of pointers */
-#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
-    fd, pb_delta(st, m ## _count, m), \
-    pb_membersize(st, m[0]), 0, ptr}
-
-/* Callbacks are much like required fields except with special datatype. */
-#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-
-#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-    
-#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
 
 
-/* Optional extensions don't have the has_ field, as that would be redundant. */
-#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
-    0, \
-    0, \
-    pb_membersize(st, m), 0, ptr}
+#define PB_FIELDINFO_1(tag, type, data_offset, data_size, size_offset, array_size) \
+    (0 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(data_offset) & 0xFF) << 16) | \
+     (((uint32_t)(size_offset) & 0x0F) << 24) | (((uint32_t)(data_size) & 0x0F) << 28)),
+
+#define PB_FIELDINFO_2(tag, type, data_offset, data_size, size_offset, array_size) \
+    (1 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFF) << 16) | (((uint32_t)(size_offset) & 0x0F) << 28)), \
+    (((uint32_t)(data_offset) & 0xFFFF) | (((uint32_t)(data_size) & 0xFFF) << 16) | (((uint32_t)(tag) & 0x2c0) << 22)),
+
+#define PB_FIELDINFO_4(tag, type, data_offset, data_size, size_offset, array_size) \
+    (2 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFFF) << 16)), \
+    ((uint32_t)(int8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
+    (data_offset), (data_size),
+
+#define PB_FIELDINFO_8(tag, type, data_offset, data_size, size_offset, array_size) \
+    (3 | (((tag) << 2) & 0xFF) | ((type) << 8)), \
+    ((uint32_t)(int8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
+    (data_offset), (data_size), (array_size)
+
+/* These assertions verify that the field information fits in the allocated space.
+ * The generator tries to automatically determine the correct width that can fit all
+ * data associated with a message. These asserts will fail only if there has been a
+ * problem in the automatic logic - this may be worth reporting as a bug. As a workaround,
+ * you can increase the descriptor width by defining PB_FIELDINFO_WIDTH or by setting
+ * descriptorsize option in .options file.
+ */
+#define PB_FITS(value,bits) ((uint32_t)(value) < ((uint32_t)1<<bits))
+#define PB_FIELDINFO_ASSERT_1(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,6) && PB_FITS(data_offset,8) && PB_FITS(size_offset,4) && PB_FITS(data_size,4) && PB_FITS(array_size,1), FIELDINFO_DOES_NOT_FIT_width1_field ## tag)
 
 
-#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
-    0, 0, pb_membersize(st, m), 0, ptr}
+#define PB_FIELDINFO_ASSERT_2(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,10) && PB_FITS(data_offset,16) && PB_FITS(size_offset,4) && PB_FITS(data_size,12) && PB_FITS(array_size,12), FIELDINFO_DOES_NOT_FIT_width2_field ## tag)
 
 
-/* The mapping from protobuf types to LTYPEs is done using these macros. */
-#define PB_LTYPE_MAP_BOOL       PB_LTYPE_VARINT
-#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_FIXED32    PB_LTYPE_FIXED32
-#define PB_LTYPE_MAP_FIXED64    PB_LTYPE_FIXED64
-#define PB_LTYPE_MAP_FLOAT      PB_LTYPE_FIXED32
-#define PB_LTYPE_MAP_INT32      PB_LTYPE_VARINT
-#define PB_LTYPE_MAP_INT64      PB_LTYPE_VARINT
-#define PB_LTYPE_MAP_MESSAGE    PB_LTYPE_SUBMESSAGE
-#define PB_LTYPE_MAP_SFIXED32   PB_LTYPE_FIXED32
-#define PB_LTYPE_MAP_SFIXED64   PB_LTYPE_FIXED64
-#define PB_LTYPE_MAP_SINT32     PB_LTYPE_SVARINT
-#define PB_LTYPE_MAP_SINT64     PB_LTYPE_SVARINT
-#define PB_LTYPE_MAP_STRING     PB_LTYPE_STRING
-#define PB_LTYPE_MAP_UINT32     PB_LTYPE_UVARINT
-#define PB_LTYPE_MAP_UINT64     PB_LTYPE_UVARINT
-#define PB_LTYPE_MAP_EXTENSION  PB_LTYPE_EXTENSION
-
-/* This is the actual macro used in field descriptions.
- * It takes these arguments:
- * - Field tag number
- * - Field type:   BOOL, BYTES, DOUBLE, ENUM, FIXED32, FIXED64,
- *                 FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
- *                 SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
- * - Field rules:  REQUIRED, OPTIONAL or REPEATED
- * - Allocation:   STATIC or CALLBACK
- * - Placement: FIRST or OTHER, depending on if this is the first field in structure.
- * - Message name
- * - Field name
- * - Previous field name (or field name again for first field)
- * - Pointer to default value or submsg fields.
+#ifndef PB_FIELD_32BIT
+/* Maximum field sizes are still 16-bit if pb_size_t is 16-bit */
+#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
+
+#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
+#else
+/* Up to 32-bit fields supported.
+ * Note that the checks are against 31 bits to avoid compiler warnings about shift wider than type in the test.
+ * I expect that there is no reasonable use for >2GB messages with nanopb anyway.
  */
  */
+#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS((int8_t)size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
 
 
-#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
-        PB_ ## rules ## _ ## allocation(tag, message, field, \
-        PB_DATAOFFSET_ ## placement(message, field, prevfield), \
-        PB_LTYPE_MAP_ ## type, ptr)
+#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS((int8_t)size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,31), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
+#endif
 
 
 
 
+/* Automatic picking of FIELDINFO width:
+ * Uses width 1 when possible, otherwise resorts to width 2.
+ */
+
+#ifndef PB_FIELDINFO_WIDTH
+#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FIELDINFO_WIDTH_ ## atype(htype, ltype)
+#define PB_FIELDINFO_WIDTH_STATIC(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype)
+#define PB_FIELDINFO_WIDTH_POINTER(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype)
+#define PB_FIELDINFO_WIDTH_CALLBACK(htype, ltype) 2
+#define PB_FIELDINFO_WIDTH_REQUIRED(ltype) PB_FIELDINFO_WIDTH_ ## ltype
+#define PB_FIELDINFO_WIDTH_SINGULAR(ltype) PB_FIELDINFO_WIDTH_ ## ltype
+#define PB_FIELDINFO_WIDTH_OPTIONAL(ltype) PB_FIELDINFO_WIDTH_ ## ltype
+#define PB_FIELDINFO_WIDTH_ONEOF(ltype) PB_FIELDINFO_WIDTH_ ## ltype
+#define PB_FIELDINFO_WIDTH_REPEATED(ltype) 2
+#define PB_FIELDINFO_WIDTH_FIXARRAY(ltype) 2
+#define PB_FIELDINFO_WIDTH_BOOL      1
+#define PB_FIELDINFO_WIDTH_BYTES     2
+#define PB_FIELDINFO_WIDTH_DOUBLE    1
+#define PB_FIELDINFO_WIDTH_ENUM      1
+#define PB_FIELDINFO_WIDTH_UENUM     1
+#define PB_FIELDINFO_WIDTH_FIXED32   1
+#define PB_FIELDINFO_WIDTH_FIXED64   1
+#define PB_FIELDINFO_WIDTH_FLOAT     1
+#define PB_FIELDINFO_WIDTH_INT32     1
+#define PB_FIELDINFO_WIDTH_INT64     1
+#define PB_FIELDINFO_WIDTH_MESSAGE   2
+#define PB_FIELDINFO_WIDTH_SFIXED32  1
+#define PB_FIELDINFO_WIDTH_SFIXED64  1
+#define PB_FIELDINFO_WIDTH_SINT32    1
+#define PB_FIELDINFO_WIDTH_SINT64    1
+#define PB_FIELDINFO_WIDTH_STRING    2
+#define PB_FIELDINFO_WIDTH_UINT32    1
+#define PB_FIELDINFO_WIDTH_UINT64    1
+#define PB_FIELDINFO_WIDTH_EXTENSION 1
+#define PB_FIELDINFO_WIDTH_FIXED_LENGTH_BYTES 2
+#else
+#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FIELDINFO_WIDTH
+#endif
+
+/* The mapping from protobuf types to LTYPEs is done using these macros. */
+#define PB_LTYPE_MAP_BOOL               PB_LTYPE_VARINT
+#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
+#define PB_LTYPE_MAP_INT32              PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_INT64              PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_MESSAGE            PB_LTYPE_SUBMESSAGE
+#define PB_LTYPE_MAP_SFIXED32           PB_LTYPE_FIXED32
+#define PB_LTYPE_MAP_SFIXED64           PB_LTYPE_FIXED64
+#define PB_LTYPE_MAP_SINT32             PB_LTYPE_SVARINT
+#define PB_LTYPE_MAP_SINT64             PB_LTYPE_SVARINT
+#define PB_LTYPE_MAP_STRING             PB_LTYPE_STRING
+#define PB_LTYPE_MAP_UINT32             PB_LTYPE_UVARINT
+#define PB_LTYPE_MAP_UINT64             PB_LTYPE_UVARINT
+#define PB_LTYPE_MAP_EXTENSION          PB_LTYPE_EXTENSION
+#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
+
 /* These macros are used for giving out error messages.
 /* These macros are used for giving out error messages.
  * They are mostly a debugging aid; the main error information
  * They are mostly a debugging aid; the main error information
  * is the true/false return value from functions.
  * is the true/false return value from functions.
  * Some code space can be saved by disabling the error
  * Some code space can be saved by disabling the error
  * messages if not used.
  * messages if not used.
+ *
+ * PB_SET_ERROR() sets the error message if none has been set yet.
+ *                msg must be a constant string literal.
+ * PB_GET_ERROR() always returns a pointer to a string.
+ * PB_RETURN_ERROR() sets the error and returns false from current
+ *                   function.
  */
  */
 #ifdef PB_NO_ERRMSG
 #ifdef PB_NO_ERRMSG
-#define PB_RETURN_ERROR(stream,msg) \
-    do {\
-        PB_UNUSED(stream); \
-        return false; \
-    } while(0)
+#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream)
 #define PB_GET_ERROR(stream) "(errmsg disabled)"
 #define PB_GET_ERROR(stream) "(errmsg disabled)"
 #else
 #else
-#define PB_RETURN_ERROR(stream,msg) \
-    do {\
-        if ((stream)->errmsg == NULL) \
-            (stream)->errmsg = (msg); \
-        return false; \
-    } while(0)
+#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg))
 #define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
 #define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
 #endif
 #endif
 
 
+#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#ifdef __cplusplus
+#if __cplusplus >= 201103L
+#define PB_CONSTEXPR constexpr
+#else  // __cplusplus >= 201103L
+#define PB_CONSTEXPR
+#endif  // __cplusplus >= 201103L
+
+#if __cplusplus >= 201703L
+#define PB_INLINE_CONSTEXPR inline constexpr
+#else  // __cplusplus >= 201703L
+#define PB_INLINE_CONSTEXPR PB_CONSTEXPR
+#endif  // __cplusplus >= 201703L
+
+namespace nanopb {
+// Each type will be partially specialized by the generator.
+template <typename GenMessageT> struct MessageDescriptor;
+}  // namespace nanopb
+#endif  /* __cplusplus */
+
 #endif
 #endif
+

+ 226 - 60
pb_common.c

@@ -5,86 +5,252 @@
 
 
 #include "pb_common.h"
 #include "pb_common.h"
 
 
-bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct)
+static bool load_descriptor_values(pb_field_iter_t *iter)
 {
 {
-    iter->start = fields;
-    iter->pos = fields;
-    iter->required_field_index = 0;
-    iter->dest_struct = dest_struct;
-    iter->pData = (char*)dest_struct + iter->pos->data_offset;
-    iter->pSize = (char*)iter->pData + iter->pos->size_offset;
-    
-    return (iter->pos->tag != 0);
-}
+    uint32_t word0;
+    uint32_t data_offset;
+    uint8_t format;
+    int8_t size_offset;
 
 
-bool pb_field_iter_next(pb_field_iter_t *iter)
-{
-    const pb_field_t *prev_field = iter->pos;
+    if (iter->index >= iter->descriptor->field_count)
+        return false;
+
+    word0 = iter->descriptor->field_info[iter->field_info_index];
+    format = word0 & 3;
+    iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
+    iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
 
 
-    if (prev_field->tag == 0)
+    if (format == 0)
     {
     {
-        /* Handle empty message types, where the first field is already the terminator.
-         * In other cases, the iter->pos never points to the terminator. */
-        return false;
+        /* 1-word format */
+        iter->array_size = 1;
+        size_offset = (int8_t)((word0 >> 24) & 0x0F);
+        data_offset = (word0 >> 16) & 0xFF;
+        iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
     }
     }
-    
-    iter->pos++;
-    
-    if (iter->pos->tag == 0)
+    else if (format == 1)
     {
     {
-        /* Wrapped back to beginning, reinitialize */
-        (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct);
-        return false;
+        /* 2-word format */
+        uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
+
+        iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
+        iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6));
+        size_offset = (int8_t)((word0 >> 28) & 0x0F);
+        data_offset = word1 & 0xFFFF;
+        iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
+    }
+    else if (format == 2)
+    {
+        /* 4-word format */
+        uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
+        uint32_t word2 = iter->descriptor->field_info[iter->field_info_index + 2];
+        uint32_t word3 = iter->descriptor->field_info[iter->field_info_index + 3];
+
+        iter->array_size = (pb_size_t)(word0 >> 16);
+        iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
+        size_offset = (int8_t)(word1 & 0xFF);
+        data_offset = word2;
+        iter->data_size = (pb_size_t)word3;
     }
     }
     else
     else
     {
     {
-        /* Increment the pointers based on previous field size */
-        size_t prev_size = prev_field->data_size;
-    
-        if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC &&
-            PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED)
-        {
-            /* In static arrays, the data_size tells the size of a single entry and
-             * array_size is the number of entries */
-            prev_size *= prev_field->array_size;
-        }
-        else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER)
+        /* 8-word format */
+        uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
+        uint32_t word2 = iter->descriptor->field_info[iter->field_info_index + 2];
+        uint32_t word3 = iter->descriptor->field_info[iter->field_info_index + 3];
+        uint32_t word4 = iter->descriptor->field_info[iter->field_info_index + 4];
+
+        iter->array_size = (pb_size_t)word4;
+        iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
+        size_offset = (int8_t)(word1 & 0xFF);
+        data_offset = word2;
+        iter->data_size = (pb_size_t)word3;
+    }
+
+    iter->pField = (char*)iter->message + data_offset;
+
+    if (size_offset)
+    {
+        iter->pSize = (char*)iter->pField - size_offset;
+    }
+    else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
+             (PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
+              PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
+    {
+        /* Fixed count array */
+        iter->pSize = &iter->array_size;
+    }
+    else
+    {
+        iter->pSize = NULL;
+    }
+
+    if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
+    {
+        iter->pData = *(void**)iter->pField;
+    }
+    else
+    {
+        iter->pData = iter->pField;
+    }
+
+    if (PB_LTYPE(iter->type) == PB_LTYPE_SUBMESSAGE)
+    {
+        iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
+    }
+    else
+    {
+        iter->submsg_desc = NULL;
+    }
+
+    return true;
+}
+
+static void advance_iterator(pb_field_iter_t *iter)
+{
+    iter->index++;
+
+    if (iter->index >= iter->descriptor->field_count)
+    {
+        /* Restart */
+        iter->index = 0;
+        iter->field_info_index = 0;
+        iter->submessage_index = 0;
+        iter->required_field_index = 0;
+    }
+    else
+    {
+        /* Increment indexes based on previous field type.
+         * All field info formats have the following fields:
+         * - lowest 2 bits tell the amount of words in the descriptor (2^n words)
+         * - bits 2..7 give the lowest bits of tag number.
+         * - bits 8..15 give the field type.
+         */
+        uint32_t prev_descriptor = iter->descriptor->field_info[iter->field_info_index];
+        pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
+        pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
+
+        iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
+
+        if (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED)
         {
         {
-            /* Pointer fields always have a constant size in the main structure.
-             * The data_size only applies to the dynamically allocated area. */
-            prev_size = sizeof(void*);
+            iter->required_field_index++;
         }
         }
-        
-        if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED)
+
+        if (PB_LTYPE(prev_type) == PB_LTYPE_SUBMESSAGE)
         {
         {
-            /* Count the required fields, in order to check their presence in the
-             * decoder. */
-            iter->required_field_index++;
+            iter->submessage_index++;
         }
         }
-    
-        iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset;
-        iter->pSize = (char*)iter->pData + iter->pos->size_offset;
-        return true;
     }
     }
 }
 }
 
 
+bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
+{
+    memset(iter, 0, sizeof(*iter));
+
+    iter->descriptor = desc;
+    iter->message = message;
+
+    return load_descriptor_values(iter);
+}
+
+bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
+{
+    const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
+    bool status;
+
+    if (PB_ATYPE(msg->field_info[0] >> 8) == PB_ATYPE_POINTER)
+    {
+        /* For pointer extensions, the pointer is stored directly
+         * in the extension structure. This avoids having an extra
+         * indirection. */
+        status = pb_field_iter_begin(iter, msg, &extension->dest);
+    }
+    else
+    {
+        status = pb_field_iter_begin(iter, msg, extension->dest);
+    }
+
+    iter->pSize = &extension->found;
+    return status;
+}
+
+bool pb_field_iter_next(pb_field_iter_t *iter)
+{
+    advance_iterator(iter);
+    (void)load_descriptor_values(iter);
+    return iter->index != 0;
+}
+
 bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
 bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
 {
 {
-    const pb_field_t *start = iter->pos;
-    
-    do {
-        if (iter->pos->tag == tag &&
-            PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION)
+    if (iter->tag == tag)
+    {
+        return true; /* Nothing to do, correct field already. */
+    }
+    else
+    {
+        pb_size_t start = iter->index;
+        uint32_t fieldinfo;
+
+        do
+        {
+            /* Advance iterator but don't load values yet */
+            advance_iterator(iter);
+
+            /* Do fast check for tag number match */
+            fieldinfo = iter->descriptor->field_info[iter->field_info_index];
+
+            if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
+            {
+                /* Good candidate, check further */
+                (void)load_descriptor_values(iter);
+
+                if (iter->tag == tag &&
+                    PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
+                {
+                    /* Found it */
+                    return true;
+                }
+            }
+        } while (iter->index != start);
+
+        /* Searched all the way back to start, and found nothing. */
+        (void)load_descriptor_values(iter);
+        return false;
+    }
+}
+
+bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
+{
+    if (field->data_size == sizeof(pb_callback_t))
+    {
+        pb_callback_t *pCallback = (pb_callback_t*)field->pData;
+
+        if (pCallback != NULL)
         {
         {
-            /* Found the wanted field */
-            return true;
+            if (istream != NULL && pCallback->funcs.decode != NULL)
+            {
+#ifdef PB_OLD_CALLBACK_STYLE
+                return pCallback->funcs.decode(istream, field, pCallback->arg);
+#else
+                return pCallback->funcs.decode(istream, field, &pCallback->arg);
+#endif
+            }
+
+            if (ostream != NULL && pCallback->funcs.encode != NULL)
+            {
+#ifdef PB_OLD_CALLBACK_STYLE
+                return pCallback->funcs.encode(ostream, field, pCallback->arg);
+#else
+                return pCallback->funcs.encode(ostream, field, &pCallback->arg);
+#endif
+            }
         }
         }
-        
-        (void)pb_field_iter_next(iter);
-    } while (iter->pos != start);
-    
-    /* Searched all the way back to start, and found nothing. */
-    return false;
+    }
+
+    return true; /* Success, but didn't do anything */
+
 }
 }
 
 
 
 

+ 4 - 12
pb_common.h

@@ -11,20 +11,12 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-/* Iterator for pb_field_t list */
-struct pb_field_iter_s {
-    const pb_field_t *start;       /* Start of the pb_field_t array */
-    const pb_field_t *pos;         /* Current position of the iterator */
-    unsigned required_field_index; /* Zero-based index that counts only the required fields */
-    void *dest_struct;             /* Pointer to start of the structure */
-    void *pData;                   /* Pointer to current field value */
-    void *pSize;                   /* Pointer to count/has field */
-};
-typedef struct pb_field_iter_s pb_field_iter_t;
-
 /* Initialize the field iterator structure to beginning.
 /* Initialize the field iterator structure to beginning.
  * Returns false if the message type is empty. */
  * Returns false if the message type is empty. */
-bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct);
+bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message);
+
+/* Get a field iterator for extension field. */
+bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension);
 
 
 /* Advance the iterator to the next field.
 /* Advance the iterator to the next field.
  * Returns false when the iterator wraps back to the first field. */
  * Returns false when the iterator wraps back to the first field. */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 434 - 233
pb_decode.c


+ 55 - 19
pb_decode.h

@@ -34,7 +34,7 @@ struct pb_istream_s
      */
      */
     int *callback;
     int *callback;
 #else
 #else
-    bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
+    bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count);
 #endif
 #endif
 
 
     void *state; /* Free field for use by callback implementation */
     void *state; /* Free field for use by callback implementation */
@@ -45,6 +45,12 @@ struct pb_istream_s
 #endif
 #endif
 };
 };
 
 
+#ifndef PB_NO_ERRMSG
+#define PB_ISTREAM_EMPTY {0,0,0,0}
+#else
+#define PB_ISTREAM_EMPTY {0,0,0}
+#endif
+
 /***************************
 /***************************
  * Main decoding functions *
  * Main decoding functions *
  ***************************/
  ***************************/
@@ -65,32 +71,48 @@ struct pb_istream_s
  *    stream = pb_istream_from_buffer(buffer, count);
  *    stream = pb_istream_from_buffer(buffer, count);
  *    pb_decode(&stream, MyMessage_fields, &msg);
  *    pb_decode(&stream, MyMessage_fields, &msg);
  */
  */
-bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
+bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct);
 
 
-/* Same as pb_decode, except does not initialize the destination structure
- * to default values. This is slightly faster if you need no default values
- * and just do memset(struct, 0, sizeof(struct)) yourself.
+/* Extended version of pb_decode, with several options to control
+ * the decoding process:
  *
  *
- * This can also be used for 'merging' two messages, i.e. update only the
- * fields that exist in the new message.
+ * PB_DECODE_NOINIT:         Do not initialize the fields to default values.
+ *                           This is slightly faster if you do not need the default
+ *                           values and instead initialize the structure to 0 using
+ *                           e.g. memset(). This can also be used for merging two
+ *                           messages, i.e. combine already existing data with new
+ *                           values.
  *
  *
- * Note: If this function returns with an error, it will not release any
- * dynamically allocated fields. You will need to call pb_release() yourself.
+ * PB_DECODE_DELIMITED:      Input message starts with the message size as varint.
+ *                           Corresponds to parseDelimitedFrom() in Google's
+ *                           protobuf API.
+ *
+ * PB_DECODE_NULLTERMINATED: Stop reading when field tag is read as 0. This allows
+ *                           reading null terminated messages.
+ *                           NOTE: Until nanopb-0.4.0, pb_decode() also allows
+ *                           null-termination. This behaviour is not supported in
+ *                           most other protobuf implementations, so PB_DECODE_DELIMITED
+ *                           is a better option for compatibility.
+ *
+ * Multiple flags can be combined with bitwise or (| operator)
  */
  */
-bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
+#define PB_DECODE_NOINIT          0x01
+#define PB_DECODE_DELIMITED       0x02
+#define PB_DECODE_NULLTERMINATED  0x04
+bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags);
 
 
-/* Same as pb_decode, except expects the stream to start with the message size
- * encoded as varint. Corresponds to parseDelimitedFrom() in Google's
- * protobuf API.
- */
-bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define pb_decode_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NOINIT)
+#define pb_decode_delimited(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED)
+#define pb_decode_delimited_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED | PB_DECODE_NOINIT)
+#define pb_decode_nullterminated(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NULLTERMINATED)
 
 
 #ifdef PB_ENABLE_MALLOC
 #ifdef PB_ENABLE_MALLOC
 /* Release any allocated pointer fields. If you use dynamic allocation, you should
 /* Release any allocated pointer fields. If you use dynamic allocation, you should
  * call this for any successfully decoded message when you are done with it. If
  * call this for any successfully decoded message when you are done with it. If
  * pb_decode() returns with an error, the message is already released.
  * pb_decode() returns with an error, the message is already released.
  */
  */
-void pb_release(const pb_field_t fields[], void *dest_struct);
+void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
 #endif
 #endif
 
 
 
 
@@ -103,12 +125,12 @@ void pb_release(const pb_field_t fields[], void *dest_struct);
  * Alternatively, you can use a custom stream that reads directly from e.g.
  * Alternatively, you can use a custom stream that reads directly from e.g.
  * a file or a network socket.
  * a file or a network socket.
  */
  */
-pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize);
+pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize);
 
 
 /* Function to read from a pb_istream_t. You can use this if you need to
 /* Function to read from a pb_istream_t. You can use this if you need to
  * read some custom header data, or to read data in field callbacks.
  * read some custom header data, or to read data in field callbacks.
  */
  */
-bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count);
+bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
 
 
 
 
 /************************************************
 /************************************************
@@ -124,23 +146,37 @@ bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
 
 
 /* Decode an integer in the varint format. This works for bool, enum, int32,
 /* Decode an integer in the varint format. This works for bool, enum, int32,
  * int64, uint32 and uint64 field types. */
  * int64, uint32 and uint64 field types. */
+#ifndef PB_WITHOUT_64BIT
 bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
 bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
+#else
+#define pb_decode_varint pb_decode_varint32
+#endif
+
+/* Decode an integer in the varint format. This works for bool, enum, int32,
+ * and uint32 field types. */
+bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
 
 
 /* Decode an integer in the zig-zagged svarint format. This works for sint32
 /* Decode an integer in the zig-zagged svarint format. This works for sint32
  * and sint64. */
  * and sint64. */
+#ifndef PB_WITHOUT_64BIT
 bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest);
 bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest);
+#else
+bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest);
+#endif
 
 
 /* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
 /* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
  * a 4-byte wide C variable. */
  * a 4-byte wide C variable. */
 bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
 bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
 
 
+#ifndef PB_WITHOUT_64BIT
 /* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
 /* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
  * a 8-byte wide C variable. */
  * a 8-byte wide C variable. */
 bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
 bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
+#endif
 
 
 /* Make a limited-length substream for reading a PB_WT_STRING field. */
 /* Make a limited-length substream for reading a PB_WT_STRING field. */
 bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
 bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
-void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
+bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 } /* extern "C" */
 } /* extern "C" */

+ 457 - 259
pb_encode.c

@@ -20,54 +20,48 @@
 /**************************************
 /**************************************
  * Declarations internal to this file *
  * Declarations internal to this file *
  **************************************/
  **************************************/
-typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
-
-static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
-static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
-static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
+static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
+static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field);
+static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field);
+static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field);
+static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field);
 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
-static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
-static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-
-/* --- Function pointers to field encoders ---
- * Order in the array must match pb_action_t LTYPE numbering.
- */
-static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
-    &pb_enc_varint,
-    &pb_enc_uvarint,
-    &pb_enc_svarint,
-    &pb_enc_fixed32,
-    &pb_enc_fixed64,
-    
-    &pb_enc_bytes,
-    &pb_enc_string,
-    &pb_enc_submessage,
-    NULL /* extensions */
-};
+static void *pb_const_cast(const void *p);
+static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high);
+static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
+
+#ifdef PB_WITHOUT_64BIT
+#define pb_int64_t int32_t
+#define pb_uint64_t uint32_t
+#else
+#define pb_int64_t int64_t
+#define pb_uint64_t uint64_t
+#endif
 
 
 /*******************************
 /*******************************
  * pb_ostream_t implementation *
  * pb_ostream_t implementation *
  *******************************/
  *******************************/
 
 
-static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
+static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
 {
 {
-    uint8_t *dest = (uint8_t*)stream->state;
+    size_t i;
+    pb_byte_t *dest = (pb_byte_t*)stream->state;
     stream->state = dest + count;
     stream->state = dest + count;
     
     
-    while (count--)
-        *dest++ = *buf++;
+    for (i = 0; i < count; i++)
+        dest[i] = buf[i];
     
     
     return true;
     return true;
 }
 }
 
 
-pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
+pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
 {
 {
     pb_ostream_t stream;
     pb_ostream_t stream;
 #ifdef PB_BUFFER_ONLY
 #ifdef PB_BUFFER_ONLY
@@ -84,7 +78,7 @@ pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
     return stream;
     return stream;
 }
 }
 
 
-bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
+bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
 {
 {
     if (stream->callback != NULL)
     if (stream->callback != NULL)
     {
     {
@@ -109,13 +103,14 @@ bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count
  *************************/
  *************************/
 
 
 /* Encode a static array. Handles the size calculations and possible packing. */
 /* Encode a static array. Handles the size calculations and possible packing. */
-static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
-                         const void *pData, size_t count, pb_encoder_t func)
+static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field)
 {
 {
-    size_t i;
-    const void *p;
+    pb_size_t i;
+    pb_size_t count;
     size_t size;
     size_t size;
-    
+
+    count = *(pb_size_t*)field->pSize;
+
     if (count == 0)
     if (count == 0)
         return true;
         return true;
 
 
@@ -131,48 +126,53 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
         /* Determine the total size of packed array. */
         /* Determine the total size of packed array. */
         if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
         if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
         {
         {
-            size = 4 * count;
+            size = 4 * (size_t)count;
         }
         }
         else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
         else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
         {
         {
-            size = 8 * count;
+            size = 8 * (size_t)count;
         }
         }
         else
         else
         { 
         { 
             pb_ostream_t sizestream = PB_OSTREAM_SIZING;
             pb_ostream_t sizestream = PB_OSTREAM_SIZING;
-            p = pData;
+            void *pData_orig = field->pData;
             for (i = 0; i < count; i++)
             for (i = 0; i < count; i++)
             {
             {
-                if (!func(&sizestream, field, p))
-                    return false;
-                p = (const char*)p + field->data_size;
+                if (!pb_enc_varint(&sizestream, field))
+                    PB_RETURN_ERROR(stream, PB_GET_ERROR(&sizestream));
+                field->pData = (char*)field->pData + field->data_size;
             }
             }
+            field->pData = pData_orig;
             size = sizestream.bytes_written;
             size = sizestream.bytes_written;
         }
         }
         
         
-        if (!pb_encode_varint(stream, (uint64_t)size))
+        if (!pb_encode_varint(stream, (pb_uint64_t)size))
             return false;
             return false;
         
         
         if (stream->callback == NULL)
         if (stream->callback == NULL)
             return pb_write(stream, NULL, size); /* Just sizing.. */
             return pb_write(stream, NULL, size); /* Just sizing.. */
         
         
         /* Write the data */
         /* Write the data */
-        p = pData;
         for (i = 0; i < count; i++)
         for (i = 0; i < count; i++)
         {
         {
-            if (!func(stream, field, p))
-                return false;
-            p = (const char*)p + field->data_size;
+            if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32 || PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
+            {
+                if (!pb_enc_fixed(stream, field))
+                    return false;
+            }
+            else
+            {
+                if (!pb_enc_varint(stream, field))
+                    return false;
+            }
+
+            field->pData = (char*)field->pData + field->data_size;
         }
         }
     }
     }
-    else
+    else /* Unpacked fields */
     {
     {
-        p = pData;
         for (i = 0; i < count; i++)
         for (i = 0; i < count; i++)
         {
         {
-            if (!pb_encode_tag_for_field(stream, field))
-                return false;
-
             /* Normally the data is stored directly in the array entries, but
             /* Normally the data is stored directly in the array entries, but
              * for pointer-type string and bytes fields, the array entries are
              * for pointer-type string and bytes fields, the array entries are
              * actually pointers themselves also. So we have to dereference once
              * actually pointers themselves also. So we have to dereference once
@@ -181,138 +181,254 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
                 (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
                 (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
                  PB_LTYPE(field->type) == PB_LTYPE_BYTES))
                  PB_LTYPE(field->type) == PB_LTYPE_BYTES))
             {
             {
-                if (!func(stream, field, *(const void* const*)p))
-                    return false;      
+                bool status;
+                void *pData_orig = field->pData;
+                field->pData = *(void* const*)field->pData;
+
+                if (!field->pData)
+                {
+                    /* Null pointer in array is treated as empty string / bytes */
+                    status = pb_encode_tag_for_field(stream, field) &&
+                             pb_encode_varint(stream, 0);
+                }
+                else
+                {
+                    status = encode_basic_field(stream, field);
+                }
+
+                field->pData = pData_orig;
+
+                if (!status)
+                    return false;
             }
             }
             else
             else
             {
             {
-                if (!func(stream, field, p))
+                if (!encode_basic_field(stream, field))
                     return false;
                     return false;
             }
             }
-            p = (const char*)p + field->data_size;
+            field->pData = (char*)field->pData + field->data_size;
         }
         }
     }
     }
     
     
     return true;
     return true;
 }
 }
 
 
-/* Encode a field with static or pointer allocation, i.e. one whose data
- * is available to the encoder directly. */
-static bool checkreturn encode_basic_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+/* In proto3, all fields are optional and are only encoded if their value is "non-zero".
+ * This function implements the check for the zero value. */
+static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field)
 {
 {
-    pb_encoder_t func;
-    const void *pSize;
-    bool implicit_has = true;
-    
-    func = PB_ENCODERS[PB_LTYPE(field->type)];
-    
-    if (field->size_offset)
-        pSize = (const char*)pData + field->size_offset;
-    else
-        pSize = &implicit_has;
+    pb_type_t type = field->type;
 
 
-    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
+    if (PB_ATYPE(type) == PB_ATYPE_STATIC)
     {
     {
-        /* pData is a pointer to the field, which contains pointer to
-         * the data. If the 2nd pointer is NULL, it is interpreted as if
-         * the has_field was false.
-         */
-        
-        pData = *(const void* const*)pData;
-        implicit_has = (pData != NULL);
-    }
+        if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
+        {
+            /* Required proto2 fields inside proto3 submessage, pretty rare case */
+            return false;
+        }
+        else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
+        {
+            /* Repeated fields inside proto3 submessage: present if count != 0 */
+            return *(const pb_size_t*)field->pSize == 0;
+        }
+        else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
+        {
+            /* Oneof fields */
+            return *(const pb_size_t*)field->pSize == 0;
+        }
+        else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
+        {
+            /* Proto2 optional fields inside proto3 submessage */
+            return *(const bool*)field->pSize == false;
+        }
 
 
-    switch (PB_HTYPE(field->type))
-    {
-        case PB_HTYPE_REQUIRED:
-            if (!pData)
-                PB_RETURN_ERROR(stream, "missing required field");
-            if (!pb_encode_tag_for_field(stream, field))
-                return false;
-            if (!func(stream, field, pData))
-                return false;
-            break;
-        
-        case PB_HTYPE_OPTIONAL:
-            if (*(const bool*)pSize)
+        /* Rest is proto3 singular fields */
+        if (PB_LTYPE(type) == PB_LTYPE_BYTES)
+        {
+            const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData;
+            return bytes->size == 0;
+        }
+        else if (PB_LTYPE(type) == PB_LTYPE_STRING)
+        {
+            return *(const char*)field->pData == '\0';
+        }
+        else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
+        {
+            /* Fixed length bytes is only empty if its length is fixed
+             * as 0. Which would be pretty strange, but we can check
+             * it anyway. */
+            return field->data_size == 0;
+        }
+        else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+        {
+            /* Check all fields in the submessage to find if any of them
+             * are non-zero. The comparison cannot be done byte-per-byte
+             * because the C struct may contain padding bytes that must
+             * be skipped.
+             */
+            pb_field_iter_t iter;
+            if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData))
             {
             {
-                if (!pb_encode_tag_for_field(stream, field))
-                    return false;
-            
-                if (!func(stream, field, pData))
-                    return false;
+                do
+                {
+                    if (!pb_check_proto3_default_value(&iter))
+                    {
+                        return false;
+                    }
+                } while (pb_field_iter_next(&iter));
             }
             }
-            break;
-        
-        case PB_HTYPE_REPEATED:
-            if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func))
+            return true;
+        }
+    }
+    
+    {
+        /* Catch-all branch that does byte-per-byte comparison for zero value.
+         *
+         * This is for all pointer fields, and for static PB_LTYPE_VARINT,
+         * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also
+         * callback fields. These all have integer or pointer value which
+         * can be compared with 0.
+         */
+        pb_size_t i;
+        const char *p = (const char*)field->pData;
+        for (i = 0; i < field->data_size; i++)
+        {
+            if (p[i] != 0)
+            {
                 return false;
                 return false;
-            break;
-        
+            }
+        }
+
+        return true;
+    }
+}
+
+/* Encode a field with static or pointer allocation, i.e. one whose data
+ * is available to the encoder directly. */
+static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field)
+{
+    if (!field->pData)
+    {
+        /* Missing pointer field */
+        return true;
+    }
+
+    if (!pb_encode_tag_for_field(stream, field))
+        return false;
+
+    switch (PB_LTYPE(field->type))
+    {
+        case PB_LTYPE_VARINT:
+        case PB_LTYPE_UVARINT:
+        case PB_LTYPE_SVARINT:
+            return pb_enc_varint(stream, field);
+
+        case PB_LTYPE_FIXED32:
+        case PB_LTYPE_FIXED64:
+            return pb_enc_fixed(stream, field);
+
+        case PB_LTYPE_BYTES:
+            return pb_enc_bytes(stream, field);
+
+        case PB_LTYPE_STRING:
+            return pb_enc_string(stream, field);
+
+        case PB_LTYPE_SUBMESSAGE:
+            return pb_enc_submessage(stream, field);
+
+        case PB_LTYPE_FIXED_LENGTH_BYTES:
+            return pb_enc_fixed_length_bytes(stream, field);
+
         default:
         default:
             PB_RETURN_ERROR(stream, "invalid field type");
             PB_RETURN_ERROR(stream, "invalid field type");
     }
     }
-    
-    return true;
 }
 }
 
 
 /* Encode a field with callback semantics. This means that a user function is
 /* Encode a field with callback semantics. This means that a user function is
  * called to provide and encode the actual data. */
  * called to provide and encode the actual data. */
-static bool checkreturn encode_callback_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
-    const pb_callback_t *callback = (const pb_callback_t*)pData;
-    
-#ifdef PB_OLD_CALLBACK_STYLE
-    const void *arg = callback->arg;
-#else
-    void * const *arg = &(callback->arg);
-#endif    
-    
-    if (callback->funcs.encode != NULL)
+    if (field->descriptor->field_callback != NULL)
     {
     {
-        if (!callback->funcs.encode(stream, field, arg))
+        if (!field->descriptor->field_callback(NULL, stream, field))
             PB_RETURN_ERROR(stream, "callback error");
             PB_RETURN_ERROR(stream, "callback error");
     }
     }
     return true;
     return true;
 }
 }
 
 
-/* Encode a single field of any callback or static type. */
-static bool checkreturn encode_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+/* Encode a single field of any callback, pointer or static type. */
+static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field)
 {
 {
-    switch (PB_ATYPE(field->type))
+    if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK)
     {
     {
-        case PB_ATYPE_STATIC:
-        case PB_ATYPE_POINTER:
-            return encode_basic_field(stream, field, pData);
-        
-        case PB_ATYPE_CALLBACK:
-            return encode_callback_field(stream, field, pData);
-        
-        default:
-            PB_RETURN_ERROR(stream, "invalid field type");
+        return encode_callback_field(stream, field);
+    }
+    else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
+    {
+        return encode_array(stream, field);
+    }
+    else if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED)
+    {
+        if (!field->pData)
+            PB_RETURN_ERROR(stream, "missing required field");
+
+        return encode_basic_field(stream, field);
+    }
+    else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
+    {
+        if (PB_ATYPE(field->type) == PB_ATYPE_STATIC)
+        {
+            if (!field->pSize)
+            {
+                /* Proto3 singular field */
+                if (pb_check_proto3_default_value(field))
+                    return true;
+            }
+            else if (*(const bool *)field->pSize == false)
+            {
+                /* Missing optional field */
+                return true;
+            }
+        }
+
+        return encode_basic_field(stream, field);
+    }
+    else if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
+    {
+        if (*(const pb_size_t*)field->pSize != field->tag)
+        {
+            /* Different type oneof field */
+            return true;
+        }
+
+        return encode_basic_field(stream, field);
+    }
+    else
+    {
+        PB_RETURN_ERROR(stream, "invalid field type");
     }
     }
 }
 }
 
 
-/* Default handler for extension fields. Expects to have a pb_field_t
- * pointer in the extension->type->arg field. */
-static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
-    const pb_extension_t *extension)
+/* Default handler for extension fields. Expects to have a pb_msgdesc_t
+ * pointer in the extension->type->arg field, pointing to a message with
+ * only one field in it.  */
+static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension)
 {
 {
-    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
-    return encode_field(stream, field, extension->dest);
+    pb_field_iter_t iter;
+
+    if (!pb_field_iter_begin_extension(&iter, (pb_extension_t*)pb_const_cast(extension)))
+        PB_RETURN_ERROR(stream, "invalid extension");
+
+    return encode_field(stream, &iter);
 }
 }
 
 
+
 /* Walk through all the registered extensions and give them a chance
 /* Walk through all the registered extensions and give them a chance
  * to encode themselves. */
  * to encode themselves. */
-static bool checkreturn encode_extension_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
-    const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
-    PB_UNUSED(field);
-    
+    const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
+
     while (extension)
     while (extension)
     {
     {
         bool status;
         bool status;
@@ -334,7 +450,7 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream,
  * Encode all fields *
  * Encode all fields *
  *********************/
  *********************/
 
 
-static void *remove_const(const void *p)
+static void *pb_const_cast(const void *p)
 {
 {
     /* Note: this casts away const, in order to use the common field iterator
     /* Note: this casts away const, in order to use the common field iterator
      * logic for both encoding and decoding. */
      * logic for both encoding and decoding. */
@@ -346,23 +462,23 @@ static void *remove_const(const void *p)
     return t.p1;
     return t.p1;
 }
 }
 
 
-bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
+bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
 {
 {
     pb_field_iter_t iter;
     pb_field_iter_t iter;
-    if (!pb_field_iter_begin(&iter, fields, remove_const(src_struct)))
+    if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct)))
         return true; /* Empty message type */
         return true; /* Empty message type */
     
     
     do {
     do {
-        if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION)
+        if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
         {
         {
             /* Special case for the extension field placeholder */
             /* Special case for the extension field placeholder */
-            if (!encode_extension_field(stream, iter.pos, iter.pData))
+            if (!encode_extension_field(stream, &iter))
                 return false;
                 return false;
         }
         }
         else
         else
         {
         {
             /* Regular field */
             /* Regular field */
-            if (!encode_field(stream, iter.pos, iter.pData))
+            if (!encode_field(stream, &iter))
                 return false;
                 return false;
         }
         }
     } while (pb_field_iter_next(&iter));
     } while (pb_field_iter_next(&iter));
@@ -370,12 +486,28 @@ bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], cons
     return true;
     return true;
 }
 }
 
 
-bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
+bool checkreturn pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags)
 {
 {
+  if ((flags & PB_ENCODE_DELIMITED) != 0)
+  {
     return pb_encode_submessage(stream, fields, src_struct);
     return pb_encode_submessage(stream, fields, src_struct);
+  }
+  else if ((flags & PB_ENCODE_NULLTERMINATED) != 0)
+  {
+    const pb_byte_t zero = 0;
+
+    if (!pb_encode(stream, fields, src_struct))
+        return false;
+
+    return pb_write(stream, &zero, 1);
+  }
+  else
+  {
+    return pb_encode(stream, fields, src_struct);
+  }
 }
 }
 
 
-bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
+bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct)
 {
 {
     pb_ostream_t stream = PB_OSTREAM_SIZING;
     pb_ostream_t stream = PB_OSTREAM_SIZING;
     
     
@@ -389,77 +521,106 @@ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *sr
 /********************
 /********************
  * Helper functions *
  * Helper functions *
  ********************/
  ********************/
-bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
+
+/* This function avoids 64-bit shifts as they are quite slow on many platforms. */
+static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high)
 {
 {
-    uint8_t buffer[10];
     size_t i = 0;
     size_t i = 0;
-    
-    if (value == 0)
-        return pb_write(stream, (uint8_t*)&value, 1);
-    
-    while (value)
+    pb_byte_t buffer[10];
+    pb_byte_t byte = (pb_byte_t)(low & 0x7F);
+    low >>= 7;
+
+    while (i < 4 && (low != 0 || high != 0))
     {
     {
-        buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
-        value >>= 7;
-        i++;
+        byte |= 0x80;
+        buffer[i++] = byte;
+        byte = (pb_byte_t)(low & 0x7F);
+        low >>= 7;
     }
     }
-    buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
-    
+
+    if (high)
+    {
+        byte = (pb_byte_t)(byte | ((high & 0x07) << 4));
+        high >>= 3;
+
+        while (high)
+        {
+            byte |= 0x80;
+            buffer[i++] = byte;
+            byte = (pb_byte_t)(high & 0x7F);
+            high >>= 7;
+        }
+    }
+
+    buffer[i++] = byte;
+
     return pb_write(stream, buffer, i);
     return pb_write(stream, buffer, i);
 }
 }
 
 
-bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
+bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
+{
+    if (value <= 0x7F)
+    {
+        /* Fast path: single byte */
+        pb_byte_t byte = (pb_byte_t)value;
+        return pb_write(stream, &byte, 1);
+    }
+    else
+    {
+#ifdef PB_WITHOUT_64BIT
+        return pb_encode_varint_32(stream, value, 0);
+#else
+        return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32));
+#endif
+    }
+}
+
+bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
 {
 {
-    uint64_t zigzagged;
+    pb_uint64_t zigzagged;
     if (value < 0)
     if (value < 0)
-        zigzagged = ~((uint64_t)value << 1);
+        zigzagged = ~((pb_uint64_t)value << 1);
     else
     else
-        zigzagged = (uint64_t)value << 1;
+        zigzagged = (pb_uint64_t)value << 1;
     
     
     return pb_encode_varint(stream, zigzagged);
     return pb_encode_varint(stream, zigzagged);
 }
 }
 
 
 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
 {
 {
-    #ifdef __BIG_ENDIAN__
-    const uint8_t *bytes = value;
-    uint8_t lebytes[4];
-    lebytes[0] = bytes[3];
-    lebytes[1] = bytes[2];
-    lebytes[2] = bytes[1];
-    lebytes[3] = bytes[0];
-    return pb_write(stream, lebytes, 4);
-    #else
-    return pb_write(stream, (const uint8_t*)value, 4);
-    #endif
+    uint32_t val = *(const uint32_t*)value;
+    pb_byte_t bytes[4];
+    bytes[0] = (pb_byte_t)(val & 0xFF);
+    bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
+    bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
+    bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
+    return pb_write(stream, bytes, 4);
 }
 }
 
 
+#ifndef PB_WITHOUT_64BIT
 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
 {
 {
-    #ifdef __BIG_ENDIAN__
-    const uint8_t *bytes = value;
-    uint8_t lebytes[8];
-    lebytes[0] = bytes[7];
-    lebytes[1] = bytes[6];
-    lebytes[2] = bytes[5];
-    lebytes[3] = bytes[4];
-    lebytes[4] = bytes[3];
-    lebytes[5] = bytes[2];
-    lebytes[6] = bytes[1];
-    lebytes[7] = bytes[0];
-    return pb_write(stream, lebytes, 8);
-    #else
-    return pb_write(stream, (const uint8_t*)value, 8);
-    #endif
+    uint64_t val = *(const uint64_t*)value;
+    pb_byte_t bytes[8];
+    bytes[0] = (pb_byte_t)(val & 0xFF);
+    bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
+    bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
+    bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
+    bytes[4] = (pb_byte_t)((val >> 32) & 0xFF);
+    bytes[5] = (pb_byte_t)((val >> 40) & 0xFF);
+    bytes[6] = (pb_byte_t)((val >> 48) & 0xFF);
+    bytes[7] = (pb_byte_t)((val >> 56) & 0xFF);
+    return pb_write(stream, bytes, 8);
 }
 }
+#endif
 
 
 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
 {
 {
-    uint64_t tag = ((uint64_t)field_number << 3) | wiretype;
+    pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype;
     return pb_encode_varint(stream, tag);
     return pb_encode_varint(stream, tag);
 }
 }
 
 
-bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
+bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field )
 {
 {
     pb_wire_type_t wiretype;
     pb_wire_type_t wiretype;
     switch (PB_LTYPE(field->type))
     switch (PB_LTYPE(field->type))
@@ -481,6 +642,7 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t
         case PB_LTYPE_BYTES:
         case PB_LTYPE_BYTES:
         case PB_LTYPE_STRING:
         case PB_LTYPE_STRING:
         case PB_LTYPE_SUBMESSAGE:
         case PB_LTYPE_SUBMESSAGE:
+        case PB_LTYPE_FIXED_LENGTH_BYTES:
             wiretype = PB_WT_STRING;
             wiretype = PB_WT_STRING;
             break;
             break;
         
         
@@ -491,15 +653,15 @@ bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t
     return pb_encode_tag(stream, wiretype, field->tag);
     return pb_encode_tag(stream, wiretype, field->tag);
 }
 }
 
 
-bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
+bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
 {
 {
-    if (!pb_encode_varint(stream, (uint64_t)size))
+    if (!pb_encode_varint(stream, (pb_uint64_t)size))
         return false;
         return false;
     
     
     return pb_write(stream, buffer, size);
     return pb_write(stream, buffer, size);
 }
 }
 
 
-bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
+bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
 {
 {
     /* First calculate the message size using a non-writing substream. */
     /* First calculate the message size using a non-writing substream. */
     pb_ostream_t substream = PB_OSTREAM_SIZING;
     pb_ostream_t substream = PB_OSTREAM_SIZING;
@@ -516,7 +678,7 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie
     
     
     size = substream.bytes_written;
     size = substream.bytes_written;
     
     
-    if (!pb_encode_varint(stream, (uint64_t)size))
+    if (!pb_encode_varint(stream, (pb_uint64_t)size))
         return false;
         return false;
     
     
     if (stream->callback == NULL)
     if (stream->callback == NULL)
@@ -551,71 +713,81 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie
 
 
 /* Field encoders */
 /* Field encoders */
 
 
-static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
-    int64_t value = 0;
-    
-    /* Cases 1 and 2 are for compilers that have smaller types for bool
-     * or enums. */
-    switch (field->data_size)
+    if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
     {
     {
-        case 1: value = *(const int8_t*)src; break;
-        case 2: value = *(const int16_t*)src; break;
-        case 4: value = *(const int32_t*)src; break;
-        case 8: value = *(const int64_t*)src; break;
-        default: PB_RETURN_ERROR(stream, "invalid data_size");
-    }
-    
-    return pb_encode_varint(stream, (uint64_t)value);
-}
+        /* Perform unsigned integer extension */
+        pb_uint64_t value = 0;
+
+        if (field->data_size == sizeof(uint_least8_t))
+            value = *(const uint_least8_t*)field->pData;
+        else if (field->data_size == sizeof(uint_least16_t))
+            value = *(const uint_least16_t*)field->pData;
+        else if (field->data_size == sizeof(uint32_t))
+            value = *(const uint32_t*)field->pData;
+        else if (field->data_size == sizeof(pb_uint64_t))
+            value = *(const pb_uint64_t*)field->pData;
+        else
+            PB_RETURN_ERROR(stream, "invalid data_size");
 
 
-static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
-    uint64_t value = 0;
-    
-    switch (field->data_size)
+        return pb_encode_varint(stream, value);
+    }
+    else
     {
     {
-        case 4: value = *(const uint32_t*)src; break;
-        case 8: value = *(const uint64_t*)src; break;
-        default: PB_RETURN_ERROR(stream, "invalid data_size");
+        /* Perform signed integer extension */
+        pb_int64_t value = 0;
+
+        if (field->data_size == sizeof(int_least8_t))
+            value = *(const int_least8_t*)field->pData;
+        else if (field->data_size == sizeof(int_least16_t))
+            value = *(const int_least16_t*)field->pData;
+        else if (field->data_size == sizeof(int32_t))
+            value = *(const int32_t*)field->pData;
+        else if (field->data_size == sizeof(pb_int64_t))
+            value = *(const pb_int64_t*)field->pData;
+        else
+            PB_RETURN_ERROR(stream, "invalid data_size");
+
+        if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
+            return pb_encode_svarint(stream, value);
+#ifdef PB_WITHOUT_64BIT
+        else if (value < 0)
+            return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1);
+#endif
+        else
+            return pb_encode_varint(stream, (pb_uint64_t)value);
+
     }
     }
-    
-    return pb_encode_varint(stream, value);
 }
 }
 
 
-static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
-    int64_t value = 0;
-    
-    switch (field->data_size)
+    if (field->data_size == sizeof(uint32_t))
     {
     {
-        case 4: value = *(const int32_t*)src; break;
-        case 8: value = *(const int64_t*)src; break;
-        default: PB_RETURN_ERROR(stream, "invalid data_size");
+        return pb_encode_fixed32(stream, field->pData);
+    }
+#ifndef PB_WITHOUT_64BIT
+    else if (field->data_size == sizeof(uint64_t))
+    {
+        return pb_encode_fixed64(stream, field->pData);
+    }
+#endif
+    else
+    {
+        PB_RETURN_ERROR(stream, "invalid data_size");
     }
     }
-    
-    return pb_encode_svarint(stream, value);
-}
-
-static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
-    PB_UNUSED(field);
-    return pb_encode_fixed64(stream, src);
 }
 }
 
 
-static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
-    PB_UNUSED(field);
-    return pb_encode_fixed32(stream, src);
-}
+    const pb_bytes_array_t *bytes = NULL;
 
 
-static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
-    const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
+    bytes = (const pb_bytes_array_t*)field->pData;
     
     
-    if (src == NULL)
+    if (bytes == NULL)
     {
     {
-        /* Threat null pointer as an empty bytes field */
+        /* Treat null pointer as an empty bytes field */
         return pb_encode_string(stream, NULL, 0);
         return pb_encode_string(stream, NULL, 0);
     }
     }
     
     
@@ -628,37 +800,63 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie
     return pb_encode_string(stream, bytes->bytes, bytes->size);
     return pb_encode_string(stream, bytes->bytes, bytes->size);
 }
 }
 
 
-static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
     size_t size = 0;
     size_t size = 0;
     size_t max_size = field->data_size;
     size_t max_size = field->data_size;
-    const char *p = (const char*)src;
+    const char *str = (const char*)field->pData;
     
     
     if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
     if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
+    {
         max_size = (size_t)-1;
         max_size = (size_t)-1;
+    }
+    else
+    {
+        /* pb_dec_string() assumes string fields end with a null
+         * terminator when the type isn't PB_ATYPE_POINTER, so we
+         * shouldn't allow more than max-1 bytes to be written to
+         * allow space for the null terminator.
+         */
+        if (max_size == 0)
+            PB_RETURN_ERROR(stream, "zero-length string");
+
+        max_size -= 1;
+    }
+
 
 
-    if (src == NULL)
+    if (str == NULL)
     {
     {
-        size = 0; /* Threat null pointer as an empty string */
+        size = 0; /* Treat null pointer as an empty string */
     }
     }
     else
     else
     {
     {
+        const char *p = str;
+
         /* strnlen() is not always available, so just use a loop */
         /* strnlen() is not always available, so just use a loop */
         while (size < max_size && *p != '\0')
         while (size < max_size && *p != '\0')
         {
         {
             size++;
             size++;
             p++;
             p++;
         }
         }
+
+        if (*p != '\0')
+        {
+            PB_RETURN_ERROR(stream, "unterminated string");
+        }
     }
     }
 
 
-    return pb_encode_string(stream, (const uint8_t*)src, size);
+    return pb_encode_string(stream, (const pb_byte_t*)str, size);
 }
 }
 
 
-static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
 {
-    if (field->ptr == NULL)
+    if (field->submsg_desc == NULL)
         PB_RETURN_ERROR(stream, "invalid field descriptor");
         PB_RETURN_ERROR(stream, "invalid field descriptor");
     
     
-    return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
+    return pb_encode_submessage(stream, field->submsg_desc, field->pData);
 }
 }
 
 
+static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
+{
+    return pb_encode_string(stream, (const pb_byte_t*)field->pData, field->data_size);
+}

+ 36 - 11
pb_encode.h

@@ -35,7 +35,7 @@ struct pb_ostream_s
      */
      */
     int *callback;
     int *callback;
 #else
 #else
-    bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
+    bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
 #endif
 #endif
     void *state;          /* Free field for use by callback implementation. */
     void *state;          /* Free field for use by callback implementation. */
     size_t max_size;      /* Limit number of output bytes written (or use SIZE_MAX). */
     size_t max_size;      /* Limit number of output bytes written (or use SIZE_MAX). */
@@ -64,16 +64,31 @@ struct pb_ostream_s
  *    stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
  *    stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
  *    pb_encode(&stream, MyMessage_fields, &msg);
  *    pb_encode(&stream, MyMessage_fields, &msg);
  */
  */
-bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
 
 
-/* Same as pb_encode, but prepends the length of the message as a varint.
- * Corresponds to writeDelimitedTo() in Google's protobuf API.
+/* Extended version of pb_encode, with several options to control the
+ * encoding process:
+ *
+ * PB_ENCODE_DELIMITED:      Prepend the length of message as a varint.
+ *                           Corresponds to writeDelimitedTo() in Google's
+ *                           protobuf API.
+ *
+ * PB_ENCODE_NULLTERMINATED: Append a null byte to the message for termination.
+ *                           NOTE: This behaviour is not supported in most other
+ *                           protobuf implementations, so PB_ENCODE_DELIMITED
+ *                           is a better option for compatibility.
  */
  */
-bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+#define PB_ENCODE_DELIMITED       0x02
+#define PB_ENCODE_NULLTERMINATED  0x04
+bool pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags);
+
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define pb_encode_delimited(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_DELIMITED)
+#define pb_encode_nullterminated(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_NULLTERMINATED)
 
 
 /* Encode the message to get the size of the encoded data, but do not store
 /* Encode the message to get the size of the encoded data, but do not store
  * the data. */
  * the data. */
-bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
+bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct);
 
 
 /**************************************
 /**************************************
  * Functions for manipulating streams *
  * Functions for manipulating streams *
@@ -86,7 +101,7 @@ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *sr
  * Alternatively, you can use a custom stream that writes directly to e.g.
  * Alternatively, you can use a custom stream that writes directly to e.g.
  * a file or a network socket.
  * a file or a network socket.
  */
  */
-pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize);
+pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize);
 
 
 /* Pseudo-stream for measuring the size of a message without actually storing
 /* Pseudo-stream for measuring the size of a message without actually storing
  * the encoded data.
  * the encoded data.
@@ -106,7 +121,7 @@ pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize);
 /* Function to write into a pb_ostream_t stream. You can use this if you need
 /* Function to write into a pb_ostream_t stream. You can use this if you need
  * to append or prepend some custom headers to the message.
  * to append or prepend some custom headers to the message.
  */
  */
-bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
+bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
 
 
 
 
 /************************************************
 /************************************************
@@ -115,7 +130,7 @@ bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
 
 
 /* Encode field header based on type and field number defined in the field
 /* Encode field header based on type and field number defined in the field
  * structure. Call this from the callback before writing out field contents. */
  * structure. Call this from the callback before writing out field contents. */
-bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field);
+bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field);
 
 
 /* Encode field header by manually specifing wire type. You need to use this
 /* 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. */
  * if you want to write out packed arrays from a callback field. */
@@ -123,29 +138,39 @@ bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field
 
 
 /* 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. */
+#ifndef PB_WITHOUT_64BIT
 bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
 bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
+#else
+bool pb_encode_varint(pb_ostream_t *stream, uint32_t value);
+#endif
 
 
 /* Encode an integer in the zig-zagged svarint format.
 /* Encode an integer in the zig-zagged svarint format.
  * This works for sint32 and sint64. */
  * This works for sint32 and sint64. */
+#ifndef PB_WITHOUT_64BIT
 bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
 bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
+#else
+bool pb_encode_svarint(pb_ostream_t *stream, int32_t value);
+#endif
 
 
 /* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
 /* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
-bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size);
+bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
 
 
 /* Encode a fixed32, sfixed32 or float value.
 /* Encode a fixed32, sfixed32 or float value.
  * You need to pass a pointer to a 4-byte wide C variable. */
  * You need to pass a pointer to a 4-byte wide C variable. */
 bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
 bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
 
 
+#ifndef PB_WITHOUT_64BIT
 /* Encode a fixed64, sfixed64 or double value.
 /* Encode a fixed64, sfixed64 or double value.
  * You need to pass a pointer to a 8-byte wide C variable. */
  * You need to pass a pointer to a 8-byte wide C variable. */
 bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
 bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
+#endif
 
 
 /* Encode a submessage field.
 /* Encode a submessage field.
  * You need to pass the pb_field_t array and pointer to struct, just like
  * You need to pass the pb_field_t array and pointer to struct, just like
  * with pb_encode(). This internally encodes the submessage twice, first to
  * with pb_encode(). This internally encodes the submessage twice, first to
  * calculate message size and then to actually write it out.
  * calculate message size and then to actually write it out.
  */
  */
-bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 } /* extern "C" */
 } /* extern "C" */

Vissa filer visades inte eftersom för många filer har ändrats