/******************************************************************************
Click on the green Run button above
*******************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include "pb_encode.h"
#include "message.pb.h"
#include "pb.h"
// Tx buffer of encoded values
uint8_t buffer[200];
/*
bool pb_callback_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char str[32];
int index = *((int *)arg[0]); // Get index from array of arguments
snprintf(str, sizeof(str), "Input_%d", index);
return pb_encode_tag_for_field(stream, field) && pb_encode_string(stream, str, strlen(str));
}
bool pb_callback_inputs(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
for (int i = 0; i < 3; i++)
{
pb_input_t msg_input;
msg_input.state = true;
msg_input.name.funcs.encode = pb_callback_string;
msg_input.name.arg = &i; // Set index parameter to callback
if (pb_encode_tag_for_field(stream, field) == false || pb_encode_submessage(stream, pb_input_t_fields, &msg_input) == false)
{
return false;
}
}
return true;
}
*/
int main(void)
{
// Create instance and fill it with default values
pb_packet_t msg = pb_packet_t_init_default;
// Set our item
msg.illuminance = 300;
//msg.revision = pb_revision_t_PB_REV_1_2;
//msg.has_voltage = true;
//msg.voltage.battery = 630;
//msg.voltage.external = 1230;
//msg.inputs.funcs.encode = pb_callback_inputs;
// Create stream and encode data
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
pb_encode(&stream, pb_packet_t_fields, &msg);
// Print buffer length and content
printf("Length: %d\n", (int) stream.bytes_written);
for (int i = 0; i < stream.bytes_written; i++)
{
printf("%02X", buffer[i]);
}
printf("\n");
return 0;
}
syntax = "proto3";
message pb_packet_t
{
uint32 luminance = 1;
}
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.5-dev */
#include "message.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(pb_input_t, pb_input_t, AUTO)
PB_BIND(pb_voltage_t, pb_voltage_t, AUTO)
PB_BIND(pb_packet_t, pb_packet_t, AUTO)
/* Common parts of the nanopb library. Most of these are quite low-level
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h.
*/
#ifndef PB_H_INCLUDED
#define PB_H_INCLUDED
/*****************************************************************
* Nanopb compilation time options. You can change these here by *
* uncommenting the lines, or on the compiler command line. *
*****************************************************************/
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 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.
* A compiler warning will tell if you need this. */
/* #define PB_MAX_REQUIRED_FIELDS 256 */
/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
/* #define PB_FIELD_32BIT 1 */
/* Disable support for error messages in order to save some code space. */
/* #define PB_NO_ERRMSG 1 */
/* Disable support for custom streams (support only memory buffers). */
/* #define PB_BUFFER_ONLY 1 */
/* Disable support for 64-bit datatypes, for compilers without int64_t
or to save some code space. */
/* #define PB_WITHOUT_64BIT 1 */
/* Don't encode scalar arrays as packed. This is only to be used when
* the decoder on the receiving side cannot process packed scalar arrays.
* Such example is older protobuf.js. */
/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */
/* Enable conversion of doubles to floats for platforms that do not
* support 64-bit doubles. Most commonly AVR. */
/* #define PB_CONVERT_DOUBLE_FLOAT 1 */
/* Check whether incoming strings are valid UTF-8 sequences. Slows down
* the string processing slightly and slightly increases code size. */
/* #define PB_VALIDATE_UTF8 1 */
/******************************************************************
* You usually don't need to change anything below this line. *
* Feel free to look around and use the defined macros, though. *
******************************************************************/
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
#define NANOPB_VERSION nanopb-0.4.4-dev
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
* - strlen, memcpy, memset functions
* - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t
* - size_t
* - bool
*
* If you don't have the standard header files, you can instead provide
* a custom header that defines or includes all this. In that case,
* define PB_SYSTEM_HEADER to the path of this file.
*/
#ifdef PB_SYSTEM_HEADER
#include PB_SYSTEM_HEADER
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#ifdef PB_ENABLE_MALLOC
#include <stdlib.h>
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Macro for defining packed structures (compiler dependent).
* This just reduces memory requirements, but is not required.
*/
#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 */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed __attribute__((packed))
#elif defined(__ICCARM__) || defined(__CC_ARM)
/* For IAR ARM and Keil MDK-ARM compilers */
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)")
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)")
# define pb_packed
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
/* For Microsoft Visual C++ */
# define PB_PACKED_STRUCT_START __pragma(pack(push, 1))
# define PB_PACKED_STRUCT_END __pragma(pack(pop))
# define pb_packed
#else
/* Unknown compiler */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#endif
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */
#ifndef PB_UNUSED
#define PB_UNUSED(x) (void)(x)
#endif
/* Harvard-architecture processors may need special attributes for storing
* field information in program memory. */
#ifndef PB_PROGMEM
#ifdef __AVR__
#include <avr/pgmspace.h>
#define PB_PROGMEM PROGMEM
#define PB_PROGMEM_READU32(x) pgm_read_dword(&x)
#else
#define PB_PROGMEM
#define PB_PROGMEM_READU32(x) (x)
#endif
#endif
/* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use
* #define PB_NO_STATIC_ASSERT to disable it.
*
* But before doing that, check carefully the error message / place where it
* comes from to see if the error has a real cause. Unfortunately the error
* message is not always very clear to read, but you can see the reason better
* in the place where the PB_STATIC_ASSERT macro was called.
*/
#ifndef PB_NO_STATIC_ASSERT
# 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
/* Static asserts disabled by PB_NO_STATIC_ASSERT */
# define PB_STATIC_ASSERT(COND,MSG)
#endif
/* Number of required fields to keep track of. */
#ifndef PB_MAX_REQUIRED_FIELDS
#define PB_MAX_REQUIRED_FIELDS 64
#endif
#if PB_MAX_REQUIRED_FIELDS < 64
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
#endif
#ifdef PB_WITHOUT_64BIT
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Cannot use doubles without 64-bit types */
#undef PB_CONVERT_DOUBLE_FLOAT
#endif
#endif
/* List of possible field types. These are used in the autogenerated code.
* Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc.
*/
typedef uint_least8_t pb_type_t;
/**** Field data types ****/
/* Numeric types */
#define PB_LTYPE_BOOL 0x00U /* bool */
#define PB_LTYPE_VARINT 0x01U /* int32, int64, enum, bool */
#define PB_LTYPE_UVARINT 0x02U /* uint32, uint64 */
#define PB_LTYPE_SVARINT 0x03U /* sint32, sint64 */
#define PB_LTYPE_FIXED32 0x04U /* fixed32, sfixed32, float */
#define PB_LTYPE_FIXED64 0x05U /* fixed64, sfixed64, double */
/* Marker for last packable field type. */
#define PB_LTYPE_LAST_PACKABLE 0x05U
/* Byte array with pre-allocated buffer.
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */
#define PB_LTYPE_BYTES 0x06U
/* String with pre-allocated buffer.
* data_size is the maximum length. */
#define PB_LTYPE_STRING 0x07U
/* Submessage
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMESSAGE 0x08U
/* Submessage with pre-decoding callback
* The pre-decoding callback is stored as pb_callback_t right before pSize.
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMSG_W_CB 0x09U
/* Extension pseudo-field
* The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x0AU
/* 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 0x0BU
/* Number of declared LTYPES */
#define PB_LTYPES_COUNT 0x0CU
#define PB_LTYPE_MASK 0x0FU
/**** Field repetition rules ****/
#define PB_HTYPE_REQUIRED 0x00U
#define PB_HTYPE_OPTIONAL 0x10U
#define PB_HTYPE_SINGULAR 0x10U
#define PB_HTYPE_REPEATED 0x20U
#define PB_HTYPE_FIXARRAY 0x20U
#define PB_HTYPE_ONEOF 0x30U
#define PB_HTYPE_MASK 0x30U
/**** Field allocation types ****/
#define PB_ATYPE_STATIC 0x00U
#define PB_ATYPE_POINTER 0x80U
#define PB_ATYPE_CALLBACK 0x40U
#define PB_ATYPE_MASK 0xC0U
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
#define PB_LTYPE_IS_SUBMSG(x) (PB_LTYPE(x) == PB_LTYPE_SUBMESSAGE || \
PB_LTYPE(x) == PB_LTYPE_SUBMSG_W_CB)
/* Data type used for storing sizes of struct fields
* and array counts.
*/
#if defined(PB_FIELD_32BIT)
typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t;
#else
typedef uint_least16_t pb_size_t;
typedef int_least16_t pb_ssize_t;
#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
* to specify struct fields.
*/
typedef struct pb_msgdesc_s pb_msgdesc_t;
struct pb_msgdesc_s {
const uint32_t *field_info;
const pb_msgdesc_t * const * 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_size_t field_count;
pb_size_t required_field_count;
pb_size_t largest_tag;
};
/* 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.
* Otherwise fixed32/fixed64 fields can break.
*
* If you get errors here, it probably means that your stdint.h is not
* correct for your platform.
*/
#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.
* 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.
*/
#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))
struct pb_bytes_array_s {
pb_size_t size;
pb_byte_t bytes[1];
};
typedef struct pb_bytes_array_s pb_bytes_array_t;
/* This structure is used for giving the callback function.
* It is stored in the message structure and filled in by the method that
* calls pb_decode.
*
* The decoding callback will be given a limited-length stream
* If the wire type was string, the length is the length of the string.
* If the wire type was a varint/fixed32/fixed64, the length is the length
* of the actual value.
* The function may be called multiple times (especially for repeated types,
* but also otherwise if the message happens to contain the field multiple
* times.)
*
* The encoding callback will receive the actual output stream.
* It should write all the data in one call, including the field tag and
* wire type. It can write multiple fields.
*
* The callback can be null if you want to skip a field.
*/
typedef struct pb_callback_s pb_callback_t;
struct pb_callback_s {
/* Callback functions receive a pointer to the arg field.
* You can access the value of the field as *arg, and modify it if needed.
*/
union {
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
} funcs;
/* Free arg for use by callback */
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. */
typedef enum {
PB_WT_VARINT = 0,
PB_WT_64BIT = 1,
PB_WT_STRING = 2,
PB_WT_32BIT = 5
} pb_wire_type_t;
/* Structure for defining the handling of unknown/extension fields.
* Usually the pb_extension_type_t structure is automatically generated,
* while the pb_extension_t structure is created by the user. However,
* if you want to catch all unknown fields, you can also create a custom
* pb_extension_type_t with your own callback.
*/
typedef struct pb_extension_type_s pb_extension_type_t;
typedef struct pb_extension_s pb_extension_t;
struct pb_extension_type_s {
/* Called for each unknown field in the message.
* If you handle the field, read off all of its data and return true.
* If you do not handle the field, do not read anything and return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*decode)(pb_istream_t *stream, pb_extension_t *extension,
uint32_t tag, pb_wire_type_t wire_type);
/* Called once after all regular fields have been encoded.
* If you have something to write, do so and return true.
* If you do not have anything to write, just return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension);
/* Free field for use by the callback. */
const void *arg;
};
struct pb_extension_s {
/* Type describing the extension field. Usually you'll initialize
* this to a pointer to the automatically generated structure. */
const pb_extension_type_t *type;
/* Destination for the decoded data. This must match the datatype
* of the extension field. */
void *dest;
/* Pointer to the next extension handler, or NULL.
* If this extension does not match a field, the next handler is
* automatically called. */
pb_extension_t *next;
/* The decoder sets this to true if the extension was found.
* Ignored for encoding. */
bool found;
};
#define pb_extension_init_zero {NULL,NULL,NULL,false}
/* Memory allocation functions to use. You can define pb_realloc and
* pb_free to custom functions if you want. */
#ifdef PB_ENABLE_MALLOC
# ifndef pb_realloc
# define pb_realloc(ptr, size) realloc(ptr, size)
# endif
# ifndef pb_free
# define pb_free(ptr) free(ptr)
# endif
#endif
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */
#define PB_PROTO_HEADER_VERSION 40
/* These macros are used to declare pb_field_t's in the constant array. */
/* Size of a structure member, in bytes. */
#define pb_membersize(st, m) (sizeof ((st*)0)->m)
/* Number of entries in an array. */
#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. */
#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
/* 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[] PB_PROGMEM = \
{ \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
0 \
}; \
const pb_msgdesc_t* const structname ## _submsg_info[] = \
{ \
msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
NULL \
}; \
const pb_msgdesc_t structname ## _msg = \
{ \
structname ## _field_info, \
structname ## _submsg_info, \
msgname ## _DEFAULT, \
msgname ## _CALLBACK, \
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
}; \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \
+ (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED)
#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \
* 0 + tag
/* X-macro for generating the entries in struct_field_info[] array. */
#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
/* X-macro for generating asserts that entries fit in struct_field_info[] array.
* The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(),
* but it is not easily reused because of how macro substitutions work. */
#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname)
#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname)
#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname)
#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname)
#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname)
#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
#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(_PB_LTYPE_ ## ltype, structname, fieldname)
#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## 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_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SI_PB_LTYPE_BOOL(t)
#define PB_SI_PB_LTYPE_BYTES(t)
#define PB_SI_PB_LTYPE_DOUBLE(t)
#define PB_SI_PB_LTYPE_ENUM(t)
#define PB_SI_PB_LTYPE_UENUM(t)
#define PB_SI_PB_LTYPE_FIXED32(t)
#define PB_SI_PB_LTYPE_FIXED64(t)
#define PB_SI_PB_LTYPE_FLOAT(t)
#define PB_SI_PB_LTYPE_INT32(t)
#define PB_SI_PB_LTYPE_INT64(t)
#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_SFIXED32(t)
#define PB_SI_PB_LTYPE_SFIXED64(t)
#define PB_SI_PB_LTYPE_SINT32(t)
#define PB_SI_PB_LTYPE_SINT64(t)
#define PB_SI_PB_LTYPE_STRING(t)
#define PB_SI_PB_LTYPE_UINT32(t)
#define PB_SI_PB_LTYPE_UINT64(t)
#define PB_SI_PB_LTYPE_EXTENSION(t)
#define PB_SI_PB_LTYPE_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_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) & 0x3c0) << 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)(int_least8_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)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
(data_offset), (data_size), (array_size), 0, 0, 0,
/* 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_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)
#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((int_least8_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((int_least8_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(size_offset,8) && PB_FITS(data_size,31) && 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,30) && PB_FITS(data_offset,31) && PB_FITS(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.
* This is used when PB_BIND() is called with "AUTO" as the argument.
* The generator will give explicit size argument when it knows that a message
* structure grows beyond 1-word format limits.
*/
#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype)
#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2
#define PB_FI_WIDTH_PB_LTYPE_BOOL 1
#define PB_FI_WIDTH_PB_LTYPE_BYTES 2
#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1
#define PB_FI_WIDTH_PB_LTYPE_ENUM 1
#define PB_FI_WIDTH_PB_LTYPE_UENUM 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1
#define PB_FI_WIDTH_PB_LTYPE_INT32 1
#define PB_FI_WIDTH_PB_LTYPE_INT64 1
#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2
#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2
#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_SINT32 1
#define PB_FI_WIDTH_PB_LTYPE_SINT64 1
#define PB_FI_WIDTH_PB_LTYPE_STRING 2
#define PB_FI_WIDTH_PB_LTYPE_UINT32 1
#define PB_FI_WIDTH_PB_LTYPE_UINT64 1
#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2
/* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL
#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_MSG_W_CB PB_LTYPE_SUBMSG_W_CB
#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.
* They are mostly a debugging aid; the main error information
* is the true/false return value from functions.
* Some code space can be saved by disabling the error
* 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
#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream)
#define PB_GET_ERROR(stream) "(errmsg disabled)"
#else
#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg))
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
#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
/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
*
* 2014 Petteri Aimonen <
[email protected]>
*/
#include "pb_common.h"
static bool load_descriptor_values(pb_field_iter_t *iter)
{
uint32_t word0;
uint32_t data_offset;
int_least8_t size_offset;
if (iter->index >= iter->descriptor->field_count)
return false;
word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
switch(word0 & 3)
{
case 0: {
/* 1-word format */
iter->array_size = 1;
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
data_offset = (word0 >> 16) & 0xFF;
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
break;
}
case 1: {
/* 2-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
data_offset = word1 & 0xFFFF;
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
break;
}
case 2: {
/* 4-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
iter->array_size = (pb_size_t)(word0 >> 16);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
default: {
/* 8-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
iter->array_size = (pb_size_t)word4;
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
}
if (!iter->message)
{
/* Avoid doing arithmetic on null pointers, it is undefined */
iter->pField = NULL;
iter->pSize = NULL;
}
else
{
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_IS_SUBMSG(iter->type))
{
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 = PB_PROGMEM_READU32(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));
/* Add to fields.
* The cast to pb_size_t is needed to avoid -Wconversion warning.
* Because the data is is constants from generator, there is no danger of overflow.
*/
iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
}
}
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;
uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
if (PB_ATYPE(word0 >> 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)
{
if (iter->tag == tag)
{
return true; /* Nothing to do, correct field already. */
}
else if (tag > iter->descriptor->largest_tag)
{
return false;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
if (tag < iter->tag)
{
/* Fields are in tag number order, so we know that tag is between
* 0 and our start position. Setting index to end forces
* advance_iterator() call below to restart from beginning. */
iter->index = iter->descriptor->field_count;
}
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for tag number match */
fieldinfo = PB_PROGMEM_READU32(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_field_iter_find_extension(pb_field_iter_t *iter)
{
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
{
return true;
}
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 field type */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
{
return load_descriptor_values(iter);
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
static void *pb_const_cast(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator
* logic for both encoding and decoding. The cast is done using union
* to avoid spurious compiler warnings. */
union {
void *p1;
const void *p2;
} t;
t.p2 = p;
return t.p1;
}
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
{
return pb_field_iter_begin(iter, desc, pb_const_cast(message));
}
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
{
return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
}
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)
{
if (istream != NULL && pCallback->funcs.decode != NULL)
{
return pCallback->funcs.decode(istream, field, &pCallback->arg);
}
if (ostream != NULL && pCallback->funcs.encode != NULL)
{
return pCallback->funcs.encode(ostream, field, &pCallback->arg);
}
}
}
return true; /* Success, but didn't do anything */
}
#ifdef PB_VALIDATE_UTF8
/* This function checks whether a string is valid UTF-8 text.
*
* Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
* Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
* Licensed under "Short code license", which allows use under MIT license or
* any compatible with it.
*/
bool pb_validate_utf8(const char *str)
{
const pb_byte_t *s = (const pb_byte_t*)str;
while (*s)
{
if (*s < 0x80)
{
/* 0xxxxxxx */
s++;
}
else if ((s[0] & 0xe0) == 0xc0)
{
/* 110XXXXx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[0] & 0xfe) == 0xc0) /* overlong? */
return false;
else
s += 2;
}
else if ((s[0] & 0xf0) == 0xe0)
{
/* 1110XXXX 10Xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
(s[0] == 0xef && s[1] == 0xbf &&
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
return false;
else
s += 3;
}
else if ((s[0] & 0xf8) == 0xf0)
{
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[3] & 0xc0) != 0x80 ||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
return false;
else
s += 4;
}
else
{
return false;
}
}
return true;
}
#endif
/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c.
* These functions are rarely needed by applications directly.
*/
#ifndef PB_COMMON_H_INCLUDED
#define PB_COMMON_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Initialize the field iterator structure to beginning.
* Returns false if the message type is empty. */
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);
/* Same as pb_field_iter_begin(), but for const message pointer.
* Note that the pointers in pb_field_iter_t will be non-const but shouldn't
* be written to when using these functions. */
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message);
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension);
/* Advance the iterator to the next field.
* Returns false when the iterator wraps back to the first field. */
bool pb_field_iter_next(pb_field_iter_t *iter);
/* Advance the iterator until it points at a field with the given tag.
* Returns false if no such field exists. */
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found.
* There can be only one extension range field per message. */
bool pb_field_iter_find_extension(pb_field_iter_t *iter);
#ifdef PB_VALIDATE_UTF8
/* Validate UTF-8 text string */
bool pb_validate_utf8(const char *s);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
/* pb_decode.c -- decode a protobuf using minimal resources
*
* 2011 Petteri Aimonen <
[email protected]>
*/
/* Use the GCC warn_unused_result attribute to check that all return values
* are propagated correctly. On other compilers and gcc before 3.4.0 just
* ignore the annotation.
*/
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
#define checkreturn
#else
#define checkreturn __attribute__((warn_unused_result))
#endif
#include "pb.h"
#include "pb_decode.h"
#include "pb_common.h"
/**************************************
* Declarations internal to this file *
**************************************/
static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof);
static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension);
static bool pb_message_set_to_defaults(pb_field_iter_t *iter);
static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_skip_varint(pb_istream_t *stream);
static bool checkreturn pb_skip_string(pb_istream_t *stream);
#ifdef PB_ENABLE_MALLOC
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);
static void initialize_pointer_field(void *pItem, pb_field_iter_t *field);
static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field);
static void pb_release_single_field(pb_field_iter_t *field);
#endif
#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
#define PB_WT_PACKED ((pb_wire_type_t)0xFF)
typedef struct {
uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32];
} pb_fields_seen_t;
/*******************************
* pb_istream_t implementation *
*******************************/
static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
size_t i;
const pb_byte_t *source = (const pb_byte_t*)stream->state;
stream->state = (pb_byte_t*)stream->state + count;
if (buf != NULL)
{
for (i = 0; i < count; i++)
buf[i] = source[i];
}
return true;
}
bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
if (count == 0)
return true;
#ifndef PB_BUFFER_ONLY
if (buf == NULL && stream->callback != buf_read)
{
/* Skip input bytes */
pb_byte_t tmp[16];
while (count > 16)
{
if (!pb_read(stream, tmp, 16))
return false;
count -= 16;
}
return pb_read(stream, tmp, count);
}
#endif
if (stream->bytes_left < count)
PB_RETURN_ERROR(stream, "end-of-stream");
#ifndef PB_BUFFER_ONLY
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#else
if (!buf_read(stream, buf, count))
return false;
#endif
stream->bytes_left -= count;
return true;
}
/* Read a single byte from input stream. buf may not be NULL.
* This is an optimization for the varint decoding. */
static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf)
{
if (stream->bytes_left == 0)
PB_RETURN_ERROR(stream, "end-of-stream");
#ifndef PB_BUFFER_ONLY
if (!stream->callback(stream, buf, 1))
PB_RETURN_ERROR(stream, "io error");
#else
*buf = *(const pb_byte_t*)stream->state;
stream->state = (pb_byte_t*)stream->state + 1;
#endif
stream->bytes_left--;
return true;
}
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen)
{
pb_istream_t stream;
/* Cast away the const from buf without a compiler error. We are
* careful to use it only in a const manner in the callbacks.
*/
union {
void *state;
const void *c_state;
} state;
#ifdef PB_BUFFER_ONLY
stream.callback = NULL;
#else
stream.callback = &buf_read;
#endif
state.c_state = buf;
stream.state = state.state;
stream.bytes_left = msglen;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
return stream;
}
/********************
* Helper functions *
********************/
static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof)
{
pb_byte_t byte;
uint32_t result;
if (!pb_readbyte(stream, &byte))
{
if (stream->bytes_left == 0)
{
if (eof)
{
*eof = true;
}
}
return false;
}
if ((byte & 0x80) == 0)
{
/* Quick case, 1 byte value */
result = byte;
}
else
{
/* Multibyte case */
uint_fast8_t bitpos = 7;
result = byte & 0x7F;
do
{
if (!pb_readbyte(stream, &byte))
return false;
if (bitpos >= 32)
{
/* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */
pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;
bool valid_extension = ((byte & 0x7F) == 0x00 ||
((result >> 31) != 0 && byte == sign_extension));
if (bitpos >= 64 || !valid_extension)
{
PB_RETURN_ERROR(stream, "varint overflow");
}
}
else
{
result |= (uint32_t)(byte & 0x7F) << bitpos;
}
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
if (bitpos == 35 && (byte & 0x70) != 0)
{
/* The last byte was at bitpos=28, so only bottom 4 bits fit. */
PB_RETURN_ERROR(stream, "varint overflow");
}
}
*dest = result;
return true;
}
bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
{
return pb_decode_varint32_eof(stream, dest, NULL);
}
#ifndef PB_WITHOUT_64BIT
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
{
pb_byte_t byte;
uint_fast8_t bitpos = 0;
uint64_t result = 0;
do
{
if (bitpos >= 64)
PB_RETURN_ERROR(stream, "varint overflow");
if (!pb_readbyte(stream, &byte))
return false;
result |= (uint64_t)(byte & 0x7F) << bitpos;
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
*dest = result;
return true;
}
#endif
bool checkreturn pb_skip_varint(pb_istream_t *stream)
{
pb_byte_t byte;
do
{
if (!pb_read(stream, &byte, 1))
return false;
} while (byte & 0x80);
return true;
}
bool checkreturn pb_skip_string(pb_istream_t *stream)
{
uint32_t length;
if (!pb_decode_varint32(stream, &length))
return false;
if ((size_t)length != length)
{
PB_RETURN_ERROR(stream, "size too large");
}
return pb_read(stream, NULL, (size_t)length);
}
bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof)
{
uint32_t temp;
*eof = false;
*wire_type = (pb_wire_type_t) 0;
*tag = 0;
if (!pb_decode_varint32_eof(stream, &temp, eof))
{
return false;
}
*tag = temp >> 3;
*wire_type = (pb_wire_type_t)(temp & 7);
return true;
}
bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type)
{
switch (wire_type)
{
case PB_WT_VARINT: return pb_skip_varint(stream);
case PB_WT_64BIT: return pb_read(stream, NULL, 8);
case PB_WT_STRING: return pb_skip_string(stream);
case PB_WT_32BIT: return pb_read(stream, NULL, 4);
default: PB_RETURN_ERROR(stream, "invalid wire_type");
}
}
/* Read a raw value to buffer, for the purpose of passing it to callback as
* a substream. Size is maximum size on call, and actual size on return.
*/
static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size)
{
size_t max_size = *size;
switch (wire_type)
{
case PB_WT_VARINT:
*size = 0;
do
{
(*size)++;
if (*size > max_size)
PB_RETURN_ERROR(stream, "varint overflow");
if (!pb_read(stream, buf, 1))
return false;
} while (*buf++ & 0x80);
return true;
case PB_WT_64BIT:
*size = 8;
return pb_read(stream, buf, 8);
case PB_WT_32BIT:
*size = 4;
return pb_read(stream, buf, 4);
case PB_WT_STRING:
/* Calling read_raw_value with a PB_WT_STRING is an error.
* Explicitly handle this case and fallthrough to default to avoid
* compiler warnings.
*/
default: PB_RETURN_ERROR(stream, "invalid wire_type");
}
}
/* Decode string length from stream and return a substream with limited length.
* Remember to close the substream using pb_close_string_substream().
*/
bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream)
{
uint32_t size;
if (!pb_decode_varint32(stream, &size))
return false;
*substream = *stream;
if (substream->bytes_left < size)
PB_RETURN_ERROR(stream, "parent stream too short");
substream->bytes_left = (size_t)size;
stream->bytes_left -= (size_t)size;
return true;
}
bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
{
if (substream->bytes_left) {
if (!pb_read(substream, NULL, substream->bytes_left))
return false;
}
stream->state = substream->state;
#ifndef PB_NO_ERRMSG
stream->errmsg = substream->errmsg;
#endif
return true;
}
/*************************
* Decode a single field *
*************************/
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_bool(stream, field);
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_varint(stream, field);
case PB_LTYPE_FIXED32:
if (wire_type != PB_WT_32BIT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_decode_fixed32(stream, field->pData);
case PB_LTYPE_FIXED64:
if (wire_type != PB_WT_64BIT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (field->data_size == sizeof(float))
{
return pb_decode_double_as_float(stream, (float*)field->pData);
}
#endif
#ifdef PB_WITHOUT_64BIT
PB_RETURN_ERROR(stream, "invalid data_size");
#else
return pb_decode_fixed64(stream, field->pData);
#endif
case PB_LTYPE_BYTES:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_bytes(stream, field);
case PB_LTYPE_STRING:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_string(stream, field);
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_submessage(stream, field);
case PB_LTYPE_FIXED_LENGTH_BYTES:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_fixed_length_bytes(stream, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
switch (PB_HTYPE(field->type))
{
case PB_HTYPE_REQUIRED:
return decode_basic_field(stream, wire_type, field);
case PB_HTYPE_OPTIONAL:
if (field->pSize != NULL)
*(bool*)field->pSize = true;
return decode_basic_field(stream, wire_type, field);
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
&& PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Packed array */
bool status = true;
pb_istream_t substream;
pb_size_t *size = (pb_size_t*)field->pSize;
field->pData = (char*)field->pField + field->data_size * (*size);
if (!pb_make_string_substream(stream, &substream))
return false;
while (substream.bytes_left > 0 && *size < field->array_size)
{
if (!decode_basic_field(&substream, PB_WT_PACKED, field))
{
status = false;
break;
}
(*size)++;
field->pData = (char*)field->pData + field->data_size;
}
if (substream.bytes_left != 0)
PB_RETURN_ERROR(stream, "array overflow");
if (!pb_close_string_substream(stream, &substream))
return false;
return status;
}
else
{
/* Repeated field */
pb_size_t *size = (pb_size_t*)field->pSize;
field->pData = (char*)field->pField + field->data_size * (*size);
if ((*size)++ >= field->array_size)
PB_RETURN_ERROR(stream, "array overflow");
return decode_basic_field(stream, wire_type, field);
}
case PB_HTYPE_ONEOF:
*(pb_size_t*)field->pSize = field->tag;
if (PB_LTYPE_IS_SUBMSG(field->type))
{
/* We memset to zero so that any callbacks are set to NULL.
* This is because the callbacks might otherwise have values
* from some other union field.
* If callbacks are needed inside oneof field, use .proto
* option submsg_callback to have a separate callback function
* that can set the fields before submessage is decoded.
* pb_dec_submessage() will set any default values. */
memset(field->pData, 0, (size_t)field->data_size);
}
return decode_basic_field(stream, wire_type, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
#ifdef PB_ENABLE_MALLOC
/* Allocate storage for the field and store the pointer at iter->pData.
* array_size is the number of entries to reserve in an array.
* Zero size is not allowed, use pb_free() for releasing.
*/
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size)
{
void *ptr = *(void**)pData;
if (data_size == 0 || array_size == 0)
PB_RETURN_ERROR(stream, "invalid size");
#ifdef __AVR__
/* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284
* Realloc to size of 1 byte can cause corruption of the malloc structures.
*/
if (data_size == 1 && array_size == 1)
{
data_size = 2;
}
#endif
/* Check for multiplication overflows.
* This code avoids the costly division if the sizes are small enough.
* Multiplication is safe as long as only half of bits are set
* in either multiplicand.
*/
{
const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
if (data_size >= check_limit || array_size >= check_limit)
{
const size_t size_max = (size_t)-1;
if (size_max / array_size < data_size)
{
PB_RETURN_ERROR(stream, "size too large");
}
}
}
/* Allocate new or expand previous allocation */
/* Note: on failure the old pointer will remain in the structure,
* the message must be freed by caller also on error return. */
ptr = pb_realloc(ptr, array_size * data_size);
if (ptr == NULL)
PB_RETURN_ERROR(stream, "realloc failed");
*(void**)pData = ptr;
return true;
}
/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */
static void initialize_pointer_field(void *pItem, pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES)
{
*(void**)pItem = NULL;
}
else if (PB_LTYPE_IS_SUBMSG(field->type))
{
/* We memset to zero so that any callbacks are set to NULL.
* Default values will be set by pb_dec_submessage(). */
memset(pItem, 0, field->data_size);
}
}
#endif
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
#ifndef PB_ENABLE_MALLOC
PB_UNUSED(wire_type);
PB_UNUSED(field);
PB_RETURN_ERROR(stream, "no malloc support");
#else
switch (PB_HTYPE(field->type))
{
case PB_HTYPE_REQUIRED:
case PB_HTYPE_OPTIONAL:
case PB_HTYPE_ONEOF:
if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL)
{
/* Duplicate field, have to release the old allocation first. */
/* FIXME: Does this work correctly for oneofs? */
pb_release_single_field(field);
}
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
*(pb_size_t*)field->pSize = field->tag;
}
if (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES)
{
/* pb_dec_string and pb_dec_bytes handle allocation themselves */
field->pData = field->pField;
return decode_basic_field(stream, wire_type, field);
}
else
{
if (!allocate_field(stream, field->pField, field->data_size, 1))
return false;
field->pData = *(void**)field->pField;
initialize_pointer_field(field->pData, field);
return decode_basic_field(stream, wire_type, field);
}
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
&& PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Packed array, multiple items come in at once. */
bool status = true;
pb_size_t *size = (pb_size_t*)field->pSize;
size_t allocated_size = *size;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
while (substream.bytes_left)
{
if (*size == PB_SIZE_MAX)
{
#ifndef PB_NO_ERRMSG
stream->errmsg = "too many array entries";
#endif
status = false;
break;
}
if ((size_t)*size + 1 > allocated_size)
{
/* Allocate more storage. This tries to guess the
* number of remaining entries. Round the division
* upwards. */
size_t remain = (substream.bytes_left - 1) / field->data_size + 1;
if (remain < PB_SIZE_MAX - allocated_size)
allocated_size += remain;
else
allocated_size += 1;
if (!allocate_field(&substream, field->pField, field->data_size, allocated_size))
{
status = false;
break;
}
}
/* Decode the array entry */
field->pData = *(char**)field->pField + field->data_size * (*size);
initialize_pointer_field(field->pData, field);
if (!decode_basic_field(&substream, PB_WT_PACKED, field))
{
status = false;
break;
}
(*size)++;
}
if (!pb_close_string_substream(stream, &substream))
return false;
return status;
}
else
{
/* Normal repeated field, i.e. only one item at a time. */
pb_size_t *size = (pb_size_t*)field->pSize;
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1)))
return false;
field->pData = *(char**)field->pField + field->data_size * (*size);
(*size)++;
initialize_pointer_field(field->pData, field);
return decode_basic_field(stream, wire_type, field);
}
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
#endif
}
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
if (!field->descriptor->field_callback)
return pb_skip_field(stream, wire_type);
if (wire_type == PB_WT_STRING)
{
pb_istream_t substream;
size_t prev_bytes_left;
if (!pb_make_string_substream(stream, &substream))
return false;
do
{
prev_bytes_left = substream.bytes_left;
if (!field->descriptor->field_callback(&substream, NULL, field))
PB_RETURN_ERROR(stream, "callback failed");
} while (substream.bytes_left > 0 && substream.bytes_left < prev_bytes_left);
if (!pb_close_string_substream(stream, &substream))
return false;
return true;
}
else
{
/* Copy the single scalar value to stack.
* This is required so that we can limit the stream length,
* which in turn allows to use same callback for packed and
* not-packed fields. */
pb_istream_t substream;
pb_byte_t buffer[10];
size_t size = sizeof(buffer);
if (!read_raw_value(stream, wire_type, buffer, &size))
return false;
substream = pb_istream_from_buffer(buffer, size);
return field->descriptor->field_callback(&substream, NULL, field);
}
}
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
#ifdef PB_ENABLE_MALLOC
/* When decoding an oneof field, check if there is old data that must be
* released first. */
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
if (!pb_release_union_field(stream, field))
return false;
}
#endif
switch (PB_ATYPE(field->type))
{
case PB_ATYPE_STATIC:
return decode_static_field(stream, wire_type, field);
case PB_ATYPE_POINTER:
return decode_pointer_field(stream, wire_type, field);
case PB_ATYPE_CALLBACK:
return decode_callback_field(stream, wire_type, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
/* 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_decoder(pb_istream_t *stream,
pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin_extension(&iter, extension))
PB_RETURN_ERROR(stream, "invalid extension");
if (iter.tag != tag || !iter.message)
return true;
extension->found = true;
return decode_field(stream, wire_type, &iter);
}
/* Try to decode an unknown field as an extension field. Tries each extension
* decoder in turn, until one of them handles the field or loop ends. */
static bool checkreturn decode_extension(pb_istream_t *stream,
uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension)
{
size_t pos = stream->bytes_left;
while (extension != NULL && pos == stream->bytes_left)
{
bool status;
if (extension->type->decode)
status = extension->type->decode(stream, extension, tag, wire_type);
else
status = default_extension_decoder(stream, extension, tag, wire_type);
if (!status)
return false;
extension = extension->next;
}
return true;
}
/* Initialize message fields to default values, recursively */
static bool pb_field_set_to_default(pb_field_iter_t *field)
{
pb_type_t type;
type = field->type;
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
pb_extension_t *ext = *(pb_extension_t* const *)field->pData;
while (ext != NULL)
{
pb_field_iter_t ext_iter;
if (pb_field_iter_begin_extension(&ext_iter, ext))
{
ext->found = false;
if (!pb_message_set_to_defaults(&ext_iter))
return false;
}
ext = ext->next;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{
bool init_data = true;
if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
{
/* Set has_field to false. Still initialize the optional field
* itself also. */
*(bool*)field->pSize = false;
}
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
/* REPEATED: Set array count to 0, no need to initialize contents.
ONEOF: Set which_field to 0. */
*(pb_size_t*)field->pSize = 0;
init_data = false;
}
if (init_data)
{
if (PB_LTYPE_IS_SUBMSG(field->type) &&
(field->submsg_desc->default_value != NULL ||
field->submsg_desc->field_callback != NULL ||
field->submsg_desc->submsg_info[0] != NULL))
{
/* Initialize submessage to defaults.
* Only needed if it has default values
* or callback/submessage fields. */
pb_field_iter_t submsg_iter;
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
{
if (!pb_message_set_to_defaults(&submsg_iter))
return false;
}
}
else
{
/* Initialize to zeros */
memset(field->pData, 0, (size_t)field->data_size);
}
}
}
else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
/* Initialize the pointer to NULL. */
*(void**)field->pField = NULL;
/* Initialize array count to 0. */
if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
*(pb_size_t*)field->pSize = 0;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
{
/* Don't overwrite callback */
}
return true;
}
static bool pb_message_set_to_defaults(pb_field_iter_t *iter)
{
pb_istream_t defstream = PB_ISTREAM_EMPTY;
uint32_t tag = 0;
pb_wire_type_t wire_type = PB_WT_VARINT;
bool eof;
if (iter->descriptor->default_value)
{
defstream = pb_istream_from_buffer(iter->descriptor->default_value, (size_t)-1);
if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof))
return false;
}
do
{
if (!pb_field_set_to_default(iter))
return false;
if (tag != 0 && iter->tag == tag)
{
/* We have a default value for this field in the defstream */
if (!decode_field(&defstream, wire_type, iter))
return false;
if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof))
return false;
if (iter->pSize)
*(bool*)iter->pSize = false;
}
} while (pb_field_iter_next(iter));
return true;
}
/*********************
* Decode all fields *
*********************/
static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
{
uint32_t extension_range_start = 0;
pb_extension_t *extensions = NULL;
/* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed
* count field. This can only handle _one_ repeated fixed count field that
* is unpacked and unordered among other (non repeated fixed count) fields.
*/
pb_size_t fixed_count_field = PB_SIZE_MAX;
pb_size_t fixed_count_size = 0;
pb_size_t fixed_count_total_size = 0;
pb_fields_seen_t fields_seen = {{0, 0}};
const uint32_t allbits = ~(uint32_t)0;
pb_field_iter_t iter;
if (pb_field_iter_begin(&iter, fields, dest_struct))
{
if ((flags & PB_DECODE_NOINIT) == 0)
{
if (!pb_message_set_to_defaults(&iter))
PB_RETURN_ERROR(stream, "failed to set defaults");
}
}
while (stream->bytes_left)
{
uint32_t tag;
pb_wire_type_t wire_type;
bool eof;
if (!pb_decode_tag(stream, &wire_type, &tag, &eof))
{
if (eof)
break;
else
return false;
}
if (tag == 0)
{
if (flags & PB_DECODE_NULLTERMINATED)
{
break;
}
else
{
PB_RETURN_ERROR(stream, "zero tag");
}
}
if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
{
/* No match found, check if it matches an extension. */
if (extension_range_start == 0)
{
if (pb_field_iter_find_extension(&iter))
{
extensions = *(pb_extension_t* const *)iter.pData;
extension_range_start = iter.tag;
}
if (!extensions)
{
extension_range_start = (uint32_t)-1;
}
}
if (tag >= extension_range_start)
{
size_t pos = stream->bytes_left;
if (!decode_extension(stream, tag, wire_type, extensions))
return false;
if (pos != stream->bytes_left)
{
/* The field was handled */
continue;
}
}
/* No match found, skip data */
if (!pb_skip_field(stream, wire_type))
return false;
continue;
}
/* If a repeated fixed count field was found, get size from
* 'fixed_count_field' as there is no counter contained in the struct.
*/
if (PB_HTYPE(iter.type) == PB_HTYPE_REPEATED && iter.pSize == &iter.array_size)
{
if (fixed_count_field != iter.index) {
/* If the new fixed count field does not match the previous one,
* check that the previous one is NULL or that it finished
* receiving all the expected data.
*/
if (fixed_count_field != PB_SIZE_MAX &&
fixed_count_size != fixed_count_total_size)
{
PB_RETURN_ERROR(stream, "wrong size for fixed count field");
}
fixed_count_field = iter.index;
fixed_count_size = 0;
fixed_count_total_size = iter.array_size;
}
iter.pSize = &fixed_count_size;
}
if (PB_HTYPE(iter.type) == PB_HTYPE_REQUIRED
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
{
uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31));
fields_seen.bitfield[iter.required_field_index >> 5] |= tmp;
}
if (!decode_field(stream, wire_type, &iter))
return false;
}
/* Check that all elements of the last decoded fixed count field were present. */
if (fixed_count_field != PB_SIZE_MAX &&
fixed_count_size != fixed_count_total_size)
{
PB_RETURN_ERROR(stream, "wrong size for fixed count field");
}
/* Check that all required fields were present. */
{
pb_size_t req_field_count = iter.descriptor->required_field_count;
if (req_field_count > 0)
{
pb_size_t i;
if (req_field_count > PB_MAX_REQUIRED_FIELDS)
req_field_count = PB_MAX_REQUIRED_FIELDS;
/* Check the whole words */
for (i = 0; i < (req_field_count >> 5); i++)
{
if (fields_seen.bitfield[i] != allbits)
PB_RETURN_ERROR(stream, "missing required field");
}
/* Check the remaining bits (if any) */
if ((req_field_count & 31) != 0)
{
if (fields_seen.bitfield[req_field_count >> 5] !=
(allbits >> (uint_least8_t)(32 - (req_field_count & 31))))
{
PB_RETURN_ERROR(stream, "missing required field");
}
}
}
}
return true;
}
bool checkreturn pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
{
bool status;
if ((flags & PB_DECODE_DELIMITED) == 0)
{
status = pb_decode_inner(stream, fields, dest_struct, flags);
}
else
{
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
status = pb_decode_inner(&substream, fields, dest_struct, flags);
if (!pb_close_string_substream(stream, &substream))
return false;
}
#ifdef PB_ENABLE_MALLOC
if (!status)
pb_release(fields, dest_struct);
#endif
return status;
}
bool checkreturn pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct)
{
bool status;
status = pb_decode_inner(stream, fields, dest_struct, 0);
#ifdef PB_ENABLE_MALLOC
if (!status)
pb_release(fields, dest_struct);
#endif
return status;
}
#ifdef PB_ENABLE_MALLOC
/* Given an oneof field, if there has already been a field inside this oneof,
* release it before overwriting with a different one. */
static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field)
{
pb_field_iter_t old_field = *field;
pb_size_t old_tag = *(pb_size_t*)field->pSize; /* Previous which_ value */
pb_size_t new_tag = field->tag; /* New which_ value */
if (old_tag == 0)
return true; /* Ok, no old data in union */
if (old_tag == new_tag)
return true; /* Ok, old data is of same type => merge */
/* Release old data. The find can fail if the message struct contains
* invalid data. */
if (!pb_field_iter_find(&old_field, old_tag))
PB_RETURN_ERROR(stream, "invalid union tag");
pb_release_single_field(&old_field);
return true;
}
static void pb_release_single_field(pb_field_iter_t *field)
{
pb_type_t type;
type = field->type;
if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
{
if (*(pb_size_t*)field->pSize != field->tag)
return; /* This is not the current field in the union */
}
/* Release anything contained inside an extension or submsg.
* This has to be done even if the submsg itself is statically
* allocated. */
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
/* Release fields from all extensions in the linked list */
pb_extension_t *ext = *(pb_extension_t**)field->pData;
while (ext != NULL)
{
pb_field_iter_t ext_iter;
if (pb_field_iter_begin_extension(&ext_iter, ext))
{
pb_release_single_field(&ext_iter);
}
ext = ext->next;
}
}
else if (PB_LTYPE_IS_SUBMSG(type) && PB_ATYPE(type) != PB_ATYPE_CALLBACK)
{
/* Release fields in submessage or submsg array */
pb_size_t count = 1;
if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
field->pData = *(void**)field->pField;
}
else
{
field->pData = field->pField;
}
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(pb_size_t*)field->pSize;
if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > field->array_size)
{
/* Protect against corrupted _count fields */
count = field->array_size;
}
}
if (field->pData)
{
for (; count > 0; count--)
{
pb_release(field->submsg_desc, field->pData);
field->pData = (char*)field->pData + field->data_size;
}
}
}
if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
(PB_LTYPE(type) == PB_LTYPE_STRING ||
PB_LTYPE(type) == PB_LTYPE_BYTES))
{
/* Release entries in repeated string or bytes array */
void **pItem = *(void***)field->pField;
pb_size_t count = *(pb_size_t*)field->pSize;
for (; count > 0; count--)
{
pb_free(*pItem);
*pItem++ = NULL;
}
}
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
/* We are going to release the array, so set the size to 0 */
*(pb_size_t*)field->pSize = 0;
}
/* Release main pointer */
pb_free(*(void**)field->pField);
*(void**)field->pField = NULL;
}
}
void pb_release(const pb_msgdesc_t *fields, void *dest_struct)
{
pb_field_iter_t iter;
if (!dest_struct)
return; /* Ignore NULL pointers, similar to free() */
if (!pb_field_iter_begin(&iter, fields, dest_struct))
return; /* Empty message type */
do
{
pb_release_single_field(&iter);
} while (pb_field_iter_next(&iter));
}
#endif
/* Field decoders */
bool pb_decode_bool(pb_istream_t *stream, bool *dest)
{
uint32_t value;
if (!pb_decode_varint32(stream, &value))
return false;
*(bool*)dest = (value != 0);
return true;
}
bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest)
{
pb_uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
if (value & 1)
*dest = (pb_int64_t)(~(value >> 1));
else
*dest = (pb_int64_t)(value >> 1);
return true;
}
bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
{
union {
uint32_t fixed32;
pb_byte_t bytes[4];
} u;
if (!pb_read(stream, u.bytes, 4))
return false;
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
/* fast path - if we know that we're on little endian, assign directly */
*(uint32_t*)dest = u.fixed32;
#else
*(uint32_t*)dest = ((uint32_t)u.bytes[0] << 0) |
((uint32_t)u.bytes[1] << 8) |
((uint32_t)u.bytes[2] << 16) |
((uint32_t)u.bytes[3] << 24);
#endif
return true;
}
#ifndef PB_WITHOUT_64BIT
bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
{
union {
uint64_t fixed64;
pb_byte_t bytes[8];
} u;
if (!pb_read(stream, u.bytes, 8))
return false;
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
/* fast path - if we know that we're on little endian, assign directly */
*(uint64_t*)dest = u.fixed64;
#else
*(uint64_t*)dest = ((uint64_t)u.bytes[0] << 0) |
((uint64_t)u.bytes[1] << 8) |
((uint64_t)u.bytes[2] << 16) |
((uint64_t)u.bytes[3] << 24) |
((uint64_t)u.bytes[4] << 32) |
((uint64_t)u.bytes[5] << 40) |
((uint64_t)u.bytes[6] << 48) |
((uint64_t)u.bytes[7] << 56);
#endif
return true;
}
#endif
static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field)
{
return pb_decode_bool(stream, (bool*)field->pData);
}
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
{
pb_uint64_t value, clamped;
if (!pb_decode_varint(stream, &value))
return false;
/* Cast to the proper field size, while checking for overflows */
if (field->data_size == sizeof(pb_uint64_t))
clamped = *(pb_uint64_t*)field->pData = value;
else if (field->data_size == sizeof(uint32_t))
clamped = *(uint32_t*)field->pData = (uint32_t)value;
else if (field->data_size == sizeof(uint_least16_t))
clamped = *(uint_least16_t*)field->pData = (uint_least16_t)value;
else if (field->data_size == sizeof(uint_least8_t))
clamped = *(uint_least8_t*)field->pData = (uint_least8_t)value;
else
PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
return true;
}
else
{
pb_uint64_t value;
pb_int64_t svalue;
pb_int64_t clamped;
if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
{
if (!pb_decode_svarint(stream, &svalue))
return false;
}
else
{
if (!pb_decode_varint(stream, &value))
return false;
/* See issue 97: Google's C++ protobuf allows negative varint values to
* be cast as int32_t, instead of the int64_t that should be used when
* encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to
* not break decoding of such messages, we cast <=32 bit fields to
* int32_t first to get the sign correct.
*/
if (field->data_size == sizeof(pb_int64_t))
svalue = (pb_int64_t)value;
else
svalue = (int32_t)value;
}
/* Cast to the proper field size, while checking for overflows */
if (field->data_size == sizeof(pb_int64_t))
clamped = *(pb_int64_t*)field->pData = svalue;
else if (field->data_size == sizeof(int32_t))
clamped = *(int32_t*)field->pData = (int32_t)svalue;
else if (field->data_size == sizeof(int_least16_t))
clamped = *(int_least16_t*)field->pData = (int_least16_t)svalue;
else if (field->data_size == sizeof(int_least8_t))
clamped = *(int_least8_t*)field->pData = (int_least8_t)svalue;
else
PB_RETURN_ERROR(stream, "invalid data_size");
if (clamped != svalue)
PB_RETURN_ERROR(stream, "integer too large");
return true;
}
}
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
size_t alloc_size;
pb_bytes_array_t *dest;
if (!pb_decode_varint32(stream, &size))
return false;
if (size > PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "bytes overflow");
alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size);
if (size > alloc_size)
PB_RETURN_ERROR(stream, "size too large");
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
if (stream->bytes_left < size)
PB_RETURN_ERROR(stream, "end-of-stream");
if (!allocate_field(stream, field->pData, alloc_size, 1))
return false;
dest = *(pb_bytes_array_t**)field->pData;
#endif
}
else
{
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "bytes overflow");
dest = (pb_bytes_array_t*)field->pData;
}
dest->size = (pb_size_t)size;
return pb_read(stream, dest->bytes, (size_t)size);
}
static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
size_t alloc_size;
pb_byte_t *dest = (pb_byte_t*)field->pData;
if (!pb_decode_varint32(stream, &size))
return false;
if (size == (uint32_t)-1)
PB_RETURN_ERROR(stream, "size too large");
/* Space for null terminator */
alloc_size = (size_t)(size + 1);
if (alloc_size < size)
PB_RETURN_ERROR(stream, "size too large");
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
if (stream->bytes_left < size)
PB_RETURN_ERROR(stream, "end-of-stream");
if (!allocate_field(stream, field->pData, alloc_size, 1))
return false;
dest = *(pb_byte_t**)field->pData;
#endif
}
else
{
if (alloc_size > field->data_size)
PB_RETURN_ERROR(stream, "string overflow");
}
dest[size] = 0;
if (!pb_read(stream, dest, (size_t)size))
return false;
#ifdef PB_VALIDATE_UTF8
if (!pb_validate_utf8((const char*)dest))
PB_RETURN_ERROR(stream, "invalid utf8");
#endif
return true;
}
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field)
{
bool status = true;
bool submsg_consumed = false;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
if (field->submsg_desc == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor");
/* Submessages can have a separate message-level callback that is called
* before decoding the message. Typically it is used to set callback fields
* inside oneofs. */
if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
{
/* Message callback is stored right before pSize. */
pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
if (callback->funcs.decode)
{
status = callback->funcs.decode(&substream, field, &callback->arg);
if (substream.bytes_left == 0)
{
submsg_consumed = true;
}
}
}
/* Now decode the submessage contents */
if (status && !submsg_consumed)
{
unsigned int flags = 0;
/* Static required/optional fields are already initialized by top-level
* pb_decode(), no need to initialize them again. */
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_HTYPE(field->type) != PB_HTYPE_REPEATED &&
PB_HTYPE(field->type) != PB_HTYPE_ONEOF)
{
flags = PB_DECODE_NOINIT;
}
status = pb_decode_inner(&substream, field->submsg_desc, field->pData, flags);
}
if (!pb_close_string_substream(stream, &substream))
return false;
return status;
}
static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
if (!pb_decode_varint32(stream, &size))
return false;
if (size > PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "bytes overflow");
if (size == 0)
{
/* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */
memset(field->pData, 0, (size_t)field->data_size);
return true;
}
if (size != field->data_size)
PB_RETURN_ERROR(stream, "incorrect fixed length bytes size");
return pb_read(stream, (pb_byte_t*)field->pData, (size_t)field->data_size);
}
#ifdef PB_CONVERT_DOUBLE_FLOAT
bool pb_decode_double_as_float(pb_istream_t *stream, float *dest)
{
uint_least8_t sign;
int exponent;
uint32_t mantissa;
uint64_t value;
union { float f; uint32_t i; } out;
if (!pb_decode_fixed64(stream, &value))
return false;
/* Decompose input value */
sign = (uint_least8_t)((value >> 63) & 1);
exponent = (int)((value >> 52) & 0x7FF) - 1023;
mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */
/* Figure if value is in range representable by floats. */
if (exponent == 1024)
{
/* Special value */
exponent = 128;
mantissa >>= 1;
}
else
{
if (exponent > 127)
{
/* Too large, convert to infinity */
exponent = 128;
mantissa = 0;
}
else if (exponent < -150)
{
/* Too small, convert to zero */
exponent = -127;
mantissa = 0;
}
else if (exponent < -126)
{
/* Denormalized */
mantissa |= 0x1000000;
mantissa >>= (-126 - exponent);
exponent = -127;
}
/* Round off mantissa */
mantissa = (mantissa + 1) >> 1;
/* Check if mantissa went over 2.0 */
if (mantissa & 0x800000)
{
exponent += 1;
mantissa &= 0x7FFFFF;
mantissa >>= 1;
}
}
/* Combine fields */
out.i = mantissa;
out.i |= (uint32_t)(exponent + 127) << 23;
out.i |= (uint32_t)sign << 31;
*dest = out.f;
return true;
}
#endif
/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c.
* The main function is pb_decode. You also need an input stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef PB_DECODE_H_INCLUDED
#define PB_DECODE_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom input streams. You will need to provide
* a callback function to read the bytes from your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause decoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
* 3) Your callback may be used with substreams, in which case bytes_left
* is different than from the main stream. Don't use bytes_left to compute
* any pointers.
*/
struct pb_istream_s
{
#ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration.
* Having an int pointer here allows binary compatibility but
* gives an error if someone tries to assign callback function.
*/
int *callback;
#else
bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation */
size_t bytes_left;
#ifndef PB_NO_ERRMSG
const char *errmsg;
#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 *
***************************/
/* Decode a single protocol buffers message from input stream into a C structure.
* Returns true on success, false on any failure.
* The actual struct pointed to by dest must match the description in fields.
* Callback fields of the destination structure must be initialized by caller.
* All other fields will be initialized by this function.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_istream_t stream;
*
* // ... read some data into buffer ...
*
* stream = pb_istream_from_buffer(buffer, count);
* pb_decode(&stream, MyMessage_fields, &msg);
*/
bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct);
/* Extended version of pb_decode, with several options to control
* the decoding process:
*
* 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.
*
* 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)
*/
#define PB_DECODE_NOINIT 0x01U
#define PB_DECODE_DELIMITED 0x02U
#define PB_DECODE_NULLTERMINATED 0x04U
bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags);
/* 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
/* 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
* pb_decode() returns with an error, the message is already released.
*/
void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
#else
/* Allocation is not supported, so release is no-op */
#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct);
#endif
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an input stream for reading from a memory buffer.
*
* msglen should be the actual length of the message, not the full size of
* allocated buffer.
*
* Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket.
*/
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen);
/* 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.
*/
bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Decode the tag for the next field in the stream. Gives the wire type and
* field tag. At end of the message, returns false and sets eof to true. */
bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof);
/* Skip the field payload data, given the wire type. */
bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
/* Decode an integer in the varint format. This works for enum, int32,
* int64, uint32 and uint64 field types. */
#ifndef PB_WITHOUT_64BIT
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 enum, int32,
* and uint32 field types. */
bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
/* Decode a bool value in varint format. */
bool pb_decode_bool(pb_istream_t *stream, bool *dest);
/* Decode an integer in the zig-zagged svarint format. This works for sint32
* and sint64. */
#ifndef PB_WITHOUT_64BIT
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
* a 4-byte wide C variable. */
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
* a 8-byte wide C variable. */
bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
#endif
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Decode a double value into float variable. */
bool pb_decode_double_as_float(pb_istream_t *stream, float *dest);
#endif
/* 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_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
/* pb_encode.c -- encode a protobuf using minimal resources
*
* 2011 Petteri Aimonen <
[email protected]>
*/
#include "pb.h"
#include "pb_encode.h"
#include "pb_common.h"
/* Use the GCC warn_unused_result attribute to check that all return values
* are propagated correctly. On other compilers and gcc before 3.4.0 just
* ignore the annotation.
*/
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
#define checkreturn
#else
#define checkreturn __attribute__((warn_unused_result))
#endif
/**************************************
* Declarations internal to this file *
**************************************/
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 pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high);
static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field);
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 *
*******************************/
static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
size_t i;
pb_byte_t *dest = (pb_byte_t*)stream->state;
stream->state = dest + count;
for (i = 0; i < count; i++)
dest[i] = buf[i];
return true;
}
pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
{
pb_ostream_t stream;
#ifdef PB_BUFFER_ONLY
stream.callback = (void*)1; /* Just a marker value */
#else
stream.callback = &buf_write;
#endif
stream.state = buf;
stream.max_size = bufsize;
stream.bytes_written = 0;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
return stream;
}
bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
if (count > 0 && stream->callback != NULL)
{
if (stream->bytes_written + count < stream->bytes_written ||
stream->bytes_written + count > stream->max_size)
{
PB_RETURN_ERROR(stream, "stream full");
}
#ifdef PB_BUFFER_ONLY
if (!buf_write(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#else
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#endif
}
stream->bytes_written += count;
return true;
}
/*************************
* Encode a single field *
*************************/
/* Read a bool value without causing undefined behavior even if the value
* is invalid. See issue #434 and
* https://stackoverflow.com/questions/27661768/weird-results-for-conditional
*/
static bool safe_read_bool(const void *pSize)
{
const char *p = (const char *)pSize;
size_t i;
for (i = 0; i < sizeof(bool); i++)
{
if (p[i] != 0)
return true;
}
return false;
}
/* Encode a static array. Handles the size calculations and possible packing. */
static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field)
{
pb_size_t i;
pb_size_t count;
#ifndef PB_ENCODE_ARRAYS_UNPACKED
size_t size;
#endif
count = *(pb_size_t*)field->pSize;
if (count == 0)
return true;
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
PB_RETURN_ERROR(stream, "array max size exceeded");
#ifndef PB_ENCODE_ARRAYS_UNPACKED
/* We always pack arrays if the datatype allows it. */
if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
return false;
/* Determine the total size of packed array. */
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
{
size = 4 * (size_t)count;
}
else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
size = 8 * (size_t)count;
}
else
{
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
void *pData_orig = field->pData;
for (i = 0; i < count; i++)
{
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;
}
if (!pb_encode_varint(stream, (pb_uint64_t)size))
return false;
if (stream->callback == NULL)
return pb_write(stream, NULL, size); /* Just sizing.. */
/* Write the data */
for (i = 0; i < count; i++)
{
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 /* Unpacked fields */
#endif
{
for (i = 0; i < count; i++)
{
/* Normally the data is stored directly in the array entries, but
* for pointer-type string and bytes fields, the array entries are
* actually pointers themselves also. So we have to dereference once
* more to get to the actual data. */
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
(PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES))
{
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
{
if (!encode_basic_field(stream, field))
return false;
}
field->pData = (char*)field->pData + field->data_size;
}
}
return true;
}
/* 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_type_t type = field->type;
if (PB_ATYPE(type) == PB_ATYPE_STATIC)
{
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 message, or proto3
* submessage fields. */
return safe_read_bool(field->pSize) == false;
}
else if (field->descriptor->default_value)
{
/* Proto3 messages do not have default values, but proto2 messages
* can contain optional fields without has_fields (generator option 'proto3').
* In this case they must always be encoded, to make sure that the
* non-zero default value is overwritten.
*/
return false;
}
/* Rest is proto3 singular fields */
if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Simple integer / float fields */
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 true;
}
else 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_IS_SUBMSG(type))
{
/* 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. Note that usually proto3 submessages have
* a separate has_field that is checked earlier in this if.
*/
pb_field_iter_t iter;
if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData))
{
do
{
if (!pb_check_proto3_default_value(&iter))
{
return false;
}
} while (pb_field_iter_next(&iter));
}
return true;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
return field->pData == NULL;
}
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
{
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
return extension == NULL;
}
else if (field->descriptor->field_callback == pb_default_field_callback)
{
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
return pCallback->funcs.encode == NULL;
}
else
{
return field->descriptor->field_callback == NULL;
}
}
return false; /* Not typically reached, safe default for weird special cases. */
}
/* 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_BOOL:
return pb_enc_bool(stream, field);
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:
case PB_LTYPE_SUBMSG_W_CB:
return pb_enc_submessage(stream, field);
case PB_LTYPE_FIXED_LENGTH_BYTES:
return pb_enc_fixed_length_bytes(stream, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
/* Encode a field with callback semantics. This means that a user function is
* called to provide and encode the actual data. */
static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (field->descriptor->field_callback != NULL)
{
if (!field->descriptor->field_callback(NULL, stream, field))
PB_RETURN_ERROR(stream, "callback error");
}
return true;
}
/* 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)
{
/* Check field presence */
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
if (*(const pb_size_t*)field->pSize != field->tag)
{
/* Different type oneof field */
return true;
}
}
else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
{
if (field->pSize)
{
if (safe_read_bool(field->pSize) == false)
{
/* Missing optional field */
return true;
}
}
else if (PB_ATYPE(field->type) == PB_ATYPE_STATIC)
{
/* Proto3 singular field */
if (pb_check_proto3_default_value(field))
return true;
}
}
if (!field->pData)
{
if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED)
PB_RETURN_ERROR(stream, "missing required field");
/* Pointer field set to NULL */
return true;
}
/* Then encode field contents */
if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK)
{
return encode_callback_field(stream, field);
}
else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
{
return encode_array(stream, field);
}
else
{
return encode_basic_field(stream, field);
}
}
/* 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)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin_extension_const(&iter, extension))
PB_RETURN_ERROR(stream, "invalid extension");
return encode_field(stream, &iter);
}
/* Walk through all the registered extensions and give them a chance
* to encode themselves. */
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 *)field->pData;
while (extension)
{
bool status;
if (extension->type->encode)
status = extension->type->encode(stream, extension);
else
status = default_extension_encoder(stream, extension);
if (!status)
return false;
extension = extension->next;
}
return true;
}
/*********************
* Encode all fields *
*********************/
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin_const(&iter, fields, src_struct))
return true; /* Empty message type */
do {
if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
{
/* Special case for the extension field placeholder */
if (!encode_extension_field(stream, &iter))
return false;
}
else
{
/* Regular field */
if (!encode_field(stream, &iter))
return false;
}
} while (pb_field_iter_next(&iter));
return true;
}
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);
}
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_msgdesc_t *fields, const void *src_struct)
{
pb_ostream_t stream = PB_OSTREAM_SIZING;
if (!pb_encode(&stream, fields, src_struct))
return false;
*size = stream.bytes_written;
return true;
}
/********************
* Helper functions *
********************/
/* 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)
{
size_t i = 0;
pb_byte_t buffer[10];
pb_byte_t byte = (pb_byte_t)(low & 0x7F);
low >>= 7;
while (i < 4 && (low != 0 || high != 0))
{
byte |= 0x80;
buffer[i++] = byte;
byte = (pb_byte_t)(low & 0x7F);
low >>= 7;
}
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);
}
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)
{
pb_uint64_t zigzagged;
if (value < 0)
zigzagged = ~((pb_uint64_t)value << 1);
else
zigzagged = (pb_uint64_t)value << 1;
return pb_encode_varint(stream, zigzagged);
}
bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
{
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)
{
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)
{
pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype;
return pb_encode_varint(stream, tag);
}
bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field )
{
pb_wire_type_t wiretype;
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
wiretype = PB_WT_VARINT;
break;
case PB_LTYPE_FIXED32:
wiretype = PB_WT_32BIT;
break;
case PB_LTYPE_FIXED64:
wiretype = PB_WT_64BIT;
break;
case PB_LTYPE_BYTES:
case PB_LTYPE_STRING:
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
case PB_LTYPE_FIXED_LENGTH_BYTES:
wiretype = PB_WT_STRING;
break;
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
return pb_encode_tag(stream, wiretype, field->tag);
}
bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
{
if (!pb_encode_varint(stream, (pb_uint64_t)size))
return false;
return pb_write(stream, buffer, size);
}
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. */
pb_ostream_t substream = PB_OSTREAM_SIZING;
size_t size;
bool status;
if (!pb_encode(&substream, fields, src_struct))
{
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
return false;
}
size = substream.bytes_written;
if (!pb_encode_varint(stream, (pb_uint64_t)size))
return false;
if (stream->callback == NULL)
return pb_write(stream, NULL, size); /* Just sizing */
if (stream->bytes_written + size > stream->max_size)
PB_RETURN_ERROR(stream, "stream full");
/* Use a substream to verify that a callback doesn't write more than
* what it did the first time. */
substream.callback = stream->callback;
substream.state = stream->state;
substream.max_size = size;
substream.bytes_written = 0;
#ifndef PB_NO_ERRMSG
substream.errmsg = NULL;
#endif
status = pb_encode(&substream, fields, src_struct);
stream->bytes_written += substream.bytes_written;
stream->state = substream.state;
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
if (substream.bytes_written != size)
PB_RETURN_ERROR(stream, "submsg size changed");
return status;
}
/* Field encoders */
static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field)
{
uint32_t value = safe_read_bool(field->pData) ? 1 : 0;
PB_UNUSED(field);
return pb_encode_varint(stream, value);
}
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
{
/* 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");
return pb_encode_varint(stream, value);
}
else
{
/* 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);
}
}
static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
return pb_encode_float_as_double(stream, *(float*)field->pData);
}
#endif
if (field->data_size == sizeof(uint32_t))
{
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");
}
}
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
{
const pb_bytes_array_t *bytes = NULL;
bytes = (const pb_bytes_array_t*)field->pData;
if (bytes == NULL)
{
/* Treat null pointer as an empty bytes field */
return pb_encode_string(stream, NULL, 0);
}
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
{
PB_RETURN_ERROR(stream, "bytes size exceeded");
}
return pb_encode_string(stream, bytes->bytes, (size_t)bytes->size);
}
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field)
{
size_t size = 0;
size_t max_size = (size_t)field->data_size;
const char *str = (const char*)field->pData;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
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 (str == NULL)
{
size = 0; /* Treat null pointer as an empty string */
}
else
{
const char *p = str;
/* strnlen() is not always available, so just use a loop */
while (size < max_size && *p != '\0')
{
size++;
p++;
}
if (*p != '\0')
{
PB_RETURN_ERROR(stream, "unterminated string");
}
}
#ifdef PB_VALIDATE_UTF8
if (!pb_validate_utf8(str))
PB_RETURN_ERROR(stream, "invalid utf8");
#endif
return pb_encode_string(stream, (const pb_byte_t*)str, size);
}
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field)
{
if (field->submsg_desc == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor");
if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
{
/* Message callback is stored right before pSize. */
pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
if (callback->funcs.encode)
{
if (!callback->funcs.encode(stream, field, &callback->arg))
return false;
}
}
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, (size_t)field->data_size);
}
#ifdef PB_CONVERT_DOUBLE_FLOAT
bool pb_encode_float_as_double(pb_ostream_t *stream, float value)
{
union { float f; uint32_t i; } in;
uint_least8_t sign;
int exponent;
uint64_t mantissa;
in.f = value;
/* Decompose input value */
sign = (uint_least8_t)((in.i >> 31) & 1);
exponent = (int)((in.i >> 23) & 0xFF) - 127;
mantissa = in.i & 0x7FFFFF;
if (exponent == 128)
{
/* Special value (NaN etc.) */
exponent = 1024;
}
else if (exponent == -127)
{
if (!mantissa)
{
/* Zero */
exponent = -1023;
}
else
{
/* Denormalized */
mantissa <<= 1;
while (!(mantissa & 0x800000))
{
mantissa <<= 1;
exponent--;
}
mantissa &= 0x7FFFFF;
}
}
/* Combine fields */
mantissa <<= 29;
mantissa |= (uint64_t)(exponent + 1023) << 52;
mantissa |= (uint64_t)sign << 63;
return pb_encode_fixed64(stream, &mantissa);
}
#endif
/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c.
* The main function is pb_encode. You also need an output stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef PB_ENCODE_H_INCLUDED
#define PB_ENCODE_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom output streams. You will need to provide
* a callback function to write the bytes to your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause encoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer).
* 3) pb_write will update bytes_written after your callback runs.
* 4) Substreams will modify max_size and bytes_written. Don't use them
* to calculate any pointers.
*/
struct pb_ostream_s
{
#ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration.
* Having an int pointer here allows binary compatibility but
* gives an error if someone tries to assign callback function.
* Also, NULL pointer marks a 'sizing stream' that does not
* write anything.
*/
int *callback;
#else
bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
#endif
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 bytes_written; /* Number of bytes written so far. */
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
/***************************
* Main encoding functions *
***************************/
/* Encode a single protocol buffers message from C structure into a stream.
* Returns true on success, false on any failure.
* The actual struct pointed to by src_struct must match the description in fields.
* All required fields in the struct are assumed to have been filled in.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_ostream_t stream;
*
* msg.field1 = 42;
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
* pb_encode(&stream, MyMessage_fields, &msg);
*/
bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
/* 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.
*/
#define PB_ENCODE_DELIMITED 0x02U
#define PB_ENCODE_NULLTERMINATED 0x04U
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
* the data. */
bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct);
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an output stream for writing into a memory buffer.
* The number of bytes written can be found in stream.bytes_written after
* encoding the message.
*
* Alternatively, you can use a custom stream that writes directly to e.g.
* a file or a network socket.
*/
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
* the encoded data.
*
* Example usage:
* MyMessage msg = {};
* pb_ostream_t stream = PB_OSTREAM_SIZING;
* pb_encode(&stream, MyMessage_fields, &msg);
* printf("Message size is %d\n", stream.bytes_written);
*/
#ifndef PB_NO_ERRMSG
#define PB_OSTREAM_SIZING {0,0,0,0,0}
#else
#define PB_OSTREAM_SIZING {0,0,0,0}
#endif
/* 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.
*/
bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Encode field header based on type and field number defined in the field
* structure. Call this from the callback before writing out field contents. */
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
* if you want to write out packed arrays from a callback field. */
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
/* Encode an integer in the varint format.
* 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);
#else
bool pb_encode_varint(pb_ostream_t *stream, uint32_t value);
#endif
/* Encode an integer in the zig-zagged svarint format.
* This works for sint32 and sint64. */
#ifndef PB_WITHOUT_64BIT
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. */
bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
/* Encode a fixed32, sfixed32 or float value.
* You need to pass a pointer to a 4-byte wide C variable. */
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
#ifndef PB_WITHOUT_64BIT
/* Encode a fixed64, sfixed64 or double value.
* You need to pass a pointer to a 8-byte wide C variable. */
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
#endif
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Encode a float value so that it appears like a double in the encoded
* message. */
bool pb_encode_float_as_double(pb_ostream_t *stream, float value);
#endif
/* Encode a submessage field.
* 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
* calculate message size and then to actually write it out.
*/
bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.5-dev */
#ifndef PB_MESSAGE_PB_H_INCLUDED
#define PB_MESSAGE_PB_H_INCLUDED
#include "pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _pb_revision_t {
pb_revision_t_PB_REV_NONE = 0,
pb_revision_t_PB_REV_1_0 = 1,
pb_revision_t_PB_REV_1_1 = 2,
pb_revision_t_PB_REV_1_2 = 3,
pb_revision_t_PB_REV_2_0 = 4,
pb_revision_t_PB_REV_2_1 = 5
} pb_revision_t;
/* Struct definitions */
typedef struct _pb_input_t {
bool state;
pb_callback_t name;
} pb_input_t;
typedef struct _pb_voltage_t {
uint32_t battery;
uint32_t external;
} pb_voltage_t;
typedef struct _pb_packet_t {
uint32_t illuminance;
pb_revision_t revision;
pb_callback_t inputs;
bool has_voltage;
pb_voltage_t voltage;
} pb_packet_t;
/* Helper constants for enums */
#define _pb_revision_t_MIN pb_revision_t_PB_REV_NONE
#define _pb_revision_t_MAX pb_revision_t_PB_REV_2_1
#define _pb_revision_t_ARRAYSIZE ((pb_revision_t)(pb_revision_t_PB_REV_2_1+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define pb_input_t_init_default {0, {{NULL}, NULL}}
#define pb_voltage_t_init_default {0, 0}
#define pb_packet_t_init_default {0, _pb_revision_t_MIN, {{NULL}, NULL}, false, pb_voltage_t_init_default}
#define pb_input_t_init_zero {0, {{NULL}, NULL}}
#define pb_voltage_t_init_zero {0, 0}
#define pb_packet_t_init_zero {0, _pb_revision_t_MIN, {{NULL}, NULL}, false, pb_voltage_t_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define pb_input_t_state_tag 1
#define pb_input_t_name_tag 2
#define pb_voltage_t_battery_tag 1
#define pb_voltage_t_external_tag 2
#define pb_packet_t_illuminance_tag 1
#define pb_packet_t_revision_tag 2
#define pb_packet_t_inputs_tag 3
#define pb_packet_t_voltage_tag 4
/* Struct field encoding specification for nanopb */
#define pb_input_t_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, state, 1) \
X(a, CALLBACK, SINGULAR, STRING, name, 2)
#define pb_input_t_CALLBACK pb_default_field_callback
#define pb_input_t_DEFAULT NULL
#define pb_voltage_t_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, battery, 1) \
X(a, STATIC, SINGULAR, UINT32, external, 2)
#define pb_voltage_t_CALLBACK NULL
#define pb_voltage_t_DEFAULT NULL
#define pb_packet_t_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, illuminance, 1) \
X(a, STATIC, SINGULAR, UENUM, revision, 2) \
X(a, CALLBACK, REPEATED, MESSAGE, inputs, 3) \
X(a, STATIC, OPTIONAL, MESSAGE, voltage, 4)
#define pb_packet_t_CALLBACK pb_default_field_callback
#define pb_packet_t_DEFAULT NULL
#define pb_packet_t_inputs_MSGTYPE pb_input_t
#define pb_packet_t_voltage_MSGTYPE pb_voltage_t
extern const pb_msgdesc_t pb_input_t_msg;
extern const pb_msgdesc_t pb_voltage_t_msg;
extern const pb_msgdesc_t pb_packet_t_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define pb_input_t_fields &pb_input_t_msg
#define pb_voltage_t_fields &pb_voltage_t_msg
#define pb_packet_t_fields &pb_packet_t_msg
/* Maximum encoded size of messages (where known) */
/* pb_input_t_size depends on runtime parameters */
#define pb_voltage_t_size 12
/* pb_packet_t_size depends on runtime parameters */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif