diff --git a/src/protobuf/google/protobuf-c/protobuf-c.c b/src/protobuf/google/protobuf-c/protobuf-c.c index b7fc20a8..c7fb21d3 100644 --- a/src/protobuf/google/protobuf-c/protobuf-c.c +++ b/src/protobuf/google/protobuf-c/protobuf-c.c @@ -1,7 +1,6 @@ -/* --- protobuf-c.c: protobuf c runtime implementation --- */ - /* - * Copyright (c) 2008-2013, Dave Benson. All rights reserved. + * Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,21 +27,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * Todo items: +/*! \file + * Support library for `protoc-c` generated code. * - * 64-BIT OPTIMIZATION: certain implementations use 32-bit math even on 64-bit - * platforms (uint64_size, uint64_pack, parse_uint64). + * This file implements the public API used by the code generated + * by `protoc-c`. * - * get_packed_size and pack seem to use type-prefixed names, whereas parse uses - * type-suffixed names. pick one and stick with it. Decision: go with - * type-suffixed, since the type (or its instance) is typically the object of - * the verb. NOTE: perhaps the "parse" methods should be renamed to "unpack" at - * the same time. (this only affects internal (static) functions) + * \authors Dave Benson and the protobuf-c authors * - * use TRUE and FALSE instead of 1 and 0 as appropriate. + * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. + */ + +/** + * \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math + * even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64). * - * use size_t consistently. + * \todo Use size_t consistently. */ #include /* for malloc, free */ @@ -53,49 +53,88 @@ #define TRUE 1 #define FALSE 0 -/* The maximum length of a 64 bit integer in varint encoding. */ -#define MAX_UINT64_ENCODED_SIZE 10 +#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) -/* - * This should be roughly the biggest message you think you'll encounter. - * However, the only point of the hashing is to detect uninitialized required - * members. I doubt many messages have 128 REQUIRED fields, so hopefully - * this'll be fine. +/** + * \defgroup internal Internal functions and macros * - * TODO: A better solution is to separately in the descriptor index the required - * fields, and use the allocator if the required field count is too big. + * These are not exported by the library but are useful to developers working + * on `libprotobuf-c` itself. */ -#define MAX_MEMBERS_FOR_HASH_SIZE 128 + +/** + * \defgroup macros Utility macros for manipulating structures + * + * Macros and constants used to manipulate the base "classes" generated by + * `protobuf-c`. They also define limits and check correctness. + * + * \ingroup internal + * @{ + */ + +/** The maximum length of a 64-bit integer in varint encoding. */ +#define MAX_UINT64_ENCODED_SIZE 10 #ifndef PROTOBUF_C_UNPACK_ERROR # define PROTOBUF_C_UNPACK_ERROR(...) #endif +/** + * Internal `ProtobufCMessage` manipulation macro. + * + * Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and + * STRUCT_MEMBER_PTR(). + */ #define STRUCT_MEMBER_P(struct_p, struct_offset) \ ((void *) ((uint8_t *) (struct_p) + (struct_offset))) +/** + * Return field in a `ProtobufCMessage` based on offset. + * + * Take a pointer to a `ProtobufCMessage` and find the field at the offset. + * Cast it to the passed type. + */ #define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) +/** + * Return field in a `ProtobufCMessage` based on offset. + * + * Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast + * it to a pointer to the passed type. + */ #define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) /* Assertions for magic numbers. */ #define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C_ENUM_DESCRIPTOR_MAGIC) + assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC) #define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C_MESSAGE_DESCRIPTOR_MAGIC) + assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) #define ASSERT_IS_MESSAGE(message) \ ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor) #define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C_SERVICE_DESCRIPTOR_MAGIC) + assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC) -unsigned protobuf_c_major = PROTOBUF_C_MAJOR; -unsigned protobuf_c_minor = PROTOBUF_C_MINOR; +/**@}*/ + +/* --- version --- */ + +const char * +protobuf_c_version(void) +{ + return PROTOBUF_C_VERSION; +} + +uint32_t +protobuf_c_version_number(void) +{ + return PROTOBUF_C_VERSION_NUMBER; +} /* --- allocator --- */ @@ -125,11 +164,11 @@ do_free(ProtobufCAllocator *allocator, void *data) } /* - * Some users may configure the default allocator; providing your own allocator - * to unpack() is preferred. This allocator is still used for packing nested - * messages. + * This allocator uses the system's malloc() and free(). It is the default + * allocator used if NULL is passed as the ProtobufCAllocator to an exported + * function. */ -ProtobufCAllocator protobuf_c_default_allocator = { +static ProtobufCAllocator protobuf_c__allocator = { .alloc = &system_alloc, .free = &system_free, .allocator_data = NULL, @@ -145,18 +184,22 @@ protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, size_t new_len = simp->len + len; if (new_len > simp->alloced) { + ProtobufCAllocator *allocator = simp->allocator; size_t new_alloced = simp->alloced * 2; uint8_t *new_data; + + if (allocator == NULL) + allocator = &protobuf_c__allocator; while (new_alloced < new_len) new_alloced += new_alloced; - new_data = do_alloc(&protobuf_c_default_allocator, new_alloced); + new_data = do_alloc(allocator, new_alloced); if (!new_data) return; memcpy(new_data, simp->data, simp->len); if (simp->must_free_data) - do_free(&protobuf_c_default_allocator, simp->data); + do_free(allocator, simp->data); else - simp->must_free_data = 1; + simp->must_free_data = TRUE; simp->data = new_data; simp->alloced = new_alloced; } @@ -164,11 +207,23 @@ protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, simp->len = new_len; } -/* === protobuf_c_message_get_packed_size() implementation === */ +/** + * \defgroup packedsz protobuf_c_message_get_packed_size() implementation + * + * Routines mainly used by protobuf_c_message_get_packed_size(). + * + * \ingroup internal + * @{ + */ -/* +/** * Return the number of bytes required to store the tag for the field. Includes * 3 bits for the wire-type, and a single bit that denotes the end-of-tag. + * + * \param number + * Field tag to encode. + * \return + * Number of bytes required. */ static inline size_t get_tag_size(unsigned number) @@ -186,9 +241,14 @@ get_tag_size(unsigned number) } } -/* +/** * Return the number of bytes required to store a variable-length unsigned * 32-bit integer in base-128 varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. */ static inline size_t uint32_size(uint32_t v) @@ -206,9 +266,14 @@ uint32_size(uint32_t v) } } -/* +/** * Return the number of bytes required to store a variable-length signed 32-bit * integer in base-128 varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. */ static inline size_t int32_size(int32_t v) @@ -228,9 +293,14 @@ int32_size(int32_t v) } } -/* - * Return the ZigZag-encoded 32-bit unsigned integer from a 32-bit signed +/** + * Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed * integer. + * + * \param v + * Value to encode. + * \return + * ZigZag encoded integer. */ static inline uint32_t zigzag32(int32_t v) @@ -241,10 +311,15 @@ zigzag32(int32_t v) return v * 2; } -/* +/** * Return the number of bytes required to store a signed 32-bit integer, * converted to an unsigned 32-bit integer with ZigZag encoding, using base-128 * varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. */ static inline size_t sint32_size(int32_t v) @@ -252,9 +327,14 @@ sint32_size(int32_t v) return uint32_size(zigzag32(v)); } -/* +/** * Return the number of bytes required to store a 64-bit unsigned integer in * base-128 varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. */ static inline size_t uint64_size(uint64_t v) @@ -278,9 +358,14 @@ uint64_size(uint64_t v) } } -/* - * Return the ZigZag-encoded 64-bit unsigned integer from a 64-bit signed +/** + * Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed * integer. + * + * \param v + * Value to encode. + * \return + * ZigZag encoded integer. */ static inline uint64_t zigzag64(int64_t v) @@ -291,19 +376,32 @@ zigzag64(int64_t v) return v * 2; } -/* +/** * Return the number of bytes required to store a signed 64-bit integer, * converted to an unsigned 64-bit integer with ZigZag encoding, using base-128 * varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. */ -static inline size_t sint64_size(int64_t v) +static inline size_t +sint64_size(int64_t v) { return uint64_size(zigzag64(v)); } -/* +/** * Calculate the serialized size of a single required message field, including * the space needed by the preceding tag. + * + * \param field + * Field descriptor for member. + * \param member + * Field to encode. + * \return + * Number of bytes required. */ static size_t required_field_get_packed_size(const ProtobufCFieldDescriptor *field, @@ -336,7 +434,7 @@ required_field_get_packed_size(const ProtobufCFieldDescriptor *field, case PROTOBUF_C_TYPE_DOUBLE: return rv + 8; case PROTOBUF_C_TYPE_ENUM: - // TODO: is this correct for negative-valued enums? + /* \todo Is this correct for negative-valued enums? */ return rv + uint32_size(*(const uint32_t *) member); case PROTOBUF_C_TYPE_STRING: { const char *str = *(char * const *) member; @@ -347,21 +445,30 @@ required_field_get_packed_size(const ProtobufCFieldDescriptor *field, size_t len = ((const ProtobufCBinaryData *) member)->len; return rv + uint32_size(len) + len; } - //case PROTOBUF_C_TYPE_GROUP: case PROTOBUF_C_TYPE_MESSAGE: { const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0; return rv + uint32_size(subrv) + subrv; } } - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } -/* +/** * Calculate the serialized size of a single optional message field, including - * the space needed by the preceding tag. Returns 0 if the optional field isn't - * set. */ + * the space needed by the preceding tag. Returns 0 if the optional field isn't + * set. + * + * \param field + * Field descriptor for member. + * \param has + * True if the field exists, false if not. + * \param member + * Field to encode. + * \return + * Number of bytes required. + */ static size_t optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean *has, @@ -380,10 +487,19 @@ optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, return required_field_get_packed_size(field, member); } -/* +/** * Calculate the serialized size of repeated message fields, which may consist * of any number of values (including 0). Includes the space needed by the * preceding tags (as needed). + * + * \param field + * Field descriptor for member. + * \param count + * Number of repeated field members. + * \param member + * Field to encode. + * \return + * Number of bytes required. */ static size_t repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, @@ -397,7 +513,7 @@ repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, if (count == 0) return 0; header_size = get_tag_size(field->id); - if (!field->packed) + if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) header_size *= count; switch (field->type) { @@ -455,18 +571,22 @@ repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, rv += uint32_size(len) + len; } break; - //case PROTOBUF_C_TYPE_GROUP: // NOT SUPPORTED } - if (field->packed) + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) header_size += uint32_size(rv); return header_size + rv; } -/* +/** * Calculate the serialized size of an unknown field, i.e. one that is passed * through mostly uninterpreted. This is required for forward compatibility if * new fields are added to the message descriptor. + * + * \param field + * Unknown field type. + * \return + * Number of bytes required. */ static inline size_t unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) @@ -474,6 +594,8 @@ unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) return get_tag_size(field->tag) + field->len; } +/**@}*/ + /* * Calculate the serialized size of the message. */ @@ -508,11 +630,25 @@ size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) return rv; } -/* === protobuf_c_message_pack() implementation === */ +/** + * \defgroup pack protobuf_c_message_pack() implementation + * + * Routines mainly used by protobuf_c_message_pack(). + * + * \ingroup internal + * @{ + */ -/* +/** * Pack an unsigned 32-bit integer in base-128 varint encoding and return the * number of bytes written, which must be 5 or less. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t uint32_pack(uint32_t value, uint8_t *out) @@ -540,9 +676,16 @@ uint32_pack(uint32_t value, uint8_t *out) return rv; } -/* +/** * Pack a signed 32-bit integer and return the number of bytes written. * Negative numbers are encoded as two's complement 64-bit integers. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t int32_pack(int32_t value, uint8_t *out) @@ -561,9 +704,16 @@ int32_pack(int32_t value, uint8_t *out) } } -/* +/** * Pack a signed 32-bit integer using ZigZag encoding and return the number of * bytes written. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t sint32_pack(int32_t value, uint8_t *out) @@ -571,9 +721,16 @@ sint32_pack(int32_t value, uint8_t *out) return uint32_pack(zigzag32(value), out); } -/* +/** * Pack a 64-bit unsigned integer using base-128 varint encoding and return the * number of bytes written. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static size_t uint64_pack(uint64_t value, uint8_t *out) @@ -604,9 +761,16 @@ uint64_pack(uint64_t value, uint8_t *out) return rv; } -/* +/** * Pack a 64-bit signed integer in ZigZag encoding and return the number of * bytes written. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t sint64_pack(int64_t value, uint8_t *out) @@ -614,9 +778,16 @@ sint64_pack(int64_t value, uint8_t *out) return uint64_pack(zigzag64(value), out); } -/* +/** * Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire * types fixed32, sfixed32, float. Similar to "htole32". + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t fixed32_pack(uint32_t value, void *out) @@ -634,13 +805,20 @@ fixed32_pack(uint32_t value, void *out) return 4; } -/* +/** * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire * types fixed64, sfixed64, double. Similar to "htole64". * - * XXX: the big-endian impl is really only good for 32-bit machines, a 64-bit + * \todo The big-endian impl is really only good for 32-bit machines, a 64-bit * version would be appreciated, plus a way to decide to use 64-bit math where * convenient. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t fixed64_pack(uint64_t value, void *out) @@ -654,26 +832,40 @@ fixed64_pack(uint64_t value, void *out) return 8; } -/* +/** * Pack a boolean value as an integer and return the number of bytes written. * - * XXX: perhaps on some platforms "*out = !!value" would be a better impl, b/c + * \todo Perhaps on some platforms *out = !!value would be a better impl, b/c * that is idiomatic C++ in some STL implementations. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t boolean_pack(protobuf_c_boolean value, uint8_t *out) { - *out = value ? 1 : 0; + *out = value ? TRUE : FALSE; return 1; } -/* +/** * Pack a NUL-terminated C string and return the number of bytes written. The * output includes a length delimiter. * - * The NULL pointer is treated as an empty string. This isn't really necessary, - * but it allows people to leave required strings blank. (See Issue #13 in the + * The NULL pointer is treated as an empty string. This isn't really necessary, + * but it allows people to leave required strings blank. (See Issue #13 in the * bug tracker for a little more explanation). + * + * \param str + * String to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t string_pack(const char *str, uint8_t *out) @@ -689,9 +881,16 @@ string_pack(const char *str, uint8_t *out) } } -/* +/** * Pack a ProtobufCBinaryData and return the number of bytes written. The output * includes a length delimiter. + * + * \param bd + * ProtobufCBinaryData to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. */ static inline size_t binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) @@ -702,6 +901,17 @@ binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) return rv + len; } +/** + * Pack a ProtobufCMessage and return the number of bytes written. The output + * includes a length delimiter. + * + * \param message + * ProtobufCMessage object to pack. + * \param[out] out + * Packed message. + * \return + * Number of bytes written to `out`. + */ static inline size_t prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) { @@ -717,8 +927,20 @@ prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) } } -/* wire-type will be added in required_field_pack() */ -/* XXX: just call uint64_pack on 64-bit platforms. */ +/** + * Pack a field tag. + * + * Wire-type will be added in required_field_pack(). + * + * \todo Just call uint64_pack on 64-bit platforms. + * + * \param id + * Tag value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ static size_t tag_pack(uint32_t id, uint8_t *out) { @@ -728,6 +950,18 @@ tag_pack(uint32_t id, uint8_t *out) return uint64_pack(((uint64_t) id) << 3, out); } +/** + * Pack a required field and return the number of bytes written. + * + * \param field + * Field descriptor. + * \param member + * The field member. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ static size_t required_field_pack(const ProtobufCFieldDescriptor *field, const void *member, uint8_t *out) @@ -771,15 +1005,28 @@ required_field_pack(const ProtobufCFieldDescriptor *field, case PROTOBUF_C_TYPE_BYTES: out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv); - //case PROTOBUF_C_TYPE_GROUP: // NOT SUPPORTED case PROTOBUF_C_TYPE_MESSAGE: out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); } - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } +/** + * Pack an optional field and return the number of bytes written. + * + * \param field + * Field descriptor. + * \param has + * Whether the field is set. + * \param member + * The field member. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ static size_t optional_field_pack(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean *has, @@ -798,7 +1045,16 @@ optional_field_pack(const ProtobufCFieldDescriptor *field, return required_field_pack(field, member, out); } -/* TODO: implement as a table lookup */ +/** + * Given a field type, return the in-memory size. + * + * \todo Implement as a table lookup. + * + * \param type + * Field type. + * \return + * Size of the field. + */ static inline size_t sizeof_elt_in_repeated_array(ProtobufCType type) { @@ -826,10 +1082,20 @@ sizeof_elt_in_repeated_array(ProtobufCType type) case PROTOBUF_C_TYPE_BYTES: return sizeof(ProtobufCBinaryData); } - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } +/** + * Pack an array of 32-bit quantities. + * + * \param[out] out + * Destination. + * \param[in] in + * Source. + * \param[in] n + * Number of elements in the source array. + */ static void copy_to_little_endian_32(void *out, const void *in, const unsigned n) { @@ -843,6 +1109,16 @@ copy_to_little_endian_32(void *out, const void *in, const unsigned n) #endif } +/** + * Pack an array of 64-bit quantities. + * + * \param[out] out + * Destination. + * \param[in] in + * Source. + * \param[in] n + * Number of elements in the source array. + */ static void copy_to_little_endian_64(void *out, const void *in, const unsigned n) { @@ -856,6 +1132,15 @@ copy_to_little_endian_64(void *out, const void *in, const unsigned n) #endif } +/** + * Get the minimum number of bytes required to pack a field value of a + * particular type. + * + * \param type + * Field type. + * \return + * Number of bytes. + */ static unsigned get_type_min_size(ProtobufCType type) { @@ -874,14 +1159,29 @@ get_type_min_size(ProtobufCType type) return 1; } +/** + * Packs the elements of a repeated field and returns the serialised field and + * its length. + * + * \param field + * Field descriptor. + * \param count + * Number of elements in the repeated field array. + * \param member + * Pointer to the elements for this repeated field. + * \param[out] out + * Serialised representation of the repeated field. + * \return + * Number of bytes serialised to `out`. + */ static size_t repeated_field_pack(const ProtobufCFieldDescriptor *field, size_t count, const void *member, uint8_t *out) { - char *array = *(char * const *) member; + void *array = *(void * const *) member; unsigned i; - if (field->packed) { + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { unsigned header_len; unsigned len_start; unsigned min_length; @@ -952,7 +1252,7 @@ repeated_field_pack(const ProtobufCFieldDescriptor *field, break; } default: - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); } payload_len = payload_at - (out + header_len); @@ -966,14 +1266,14 @@ repeated_field_pack(const ProtobufCFieldDescriptor *field, uint32_pack(payload_len, out + len_start); return header_len + payload_len; } else { - // not "packed" cased + /* not "packed" cased */ /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ size_t rv = 0; unsigned siz = sizeof_elt_in_repeated_array(field->type); for (i = 0; i < count; i++) { rv += required_field_pack(field, array, out + rv); - array += siz; + array = (char *)array + siz; } return rv; } @@ -988,6 +1288,8 @@ unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) return rv + field->len; } +/**@}*/ + size_t protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) { @@ -1029,8 +1331,27 @@ protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) return rv; } -/* === protobuf_c_message_pack_to_buffer() implementation === */ +/** + * \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation + * + * Routines mainly used by protobuf_c_message_pack_to_buffer(). + * + * \ingroup internal + * @{ + */ +/** + * Pack a required field to a virtual buffer. + * + * \param field + * Field descriptor. + * \param member + * The element to be packed. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes packed. + */ static size_t required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const void *member, ProtobufCBuffer *buffer) @@ -1108,7 +1429,6 @@ required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, rv += sublen; break; } - //case PROTOBUF_C_TYPE_GROUP: // NOT SUPPORTED case PROTOBUF_C_TYPE_MESSAGE: { uint8_t simple_buffer_scratch[256]; size_t sublen; @@ -1129,11 +1449,25 @@ required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, break; } default: - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); } return rv; } +/** + * Pack an optional field to a buffer. + * + * \param field + * Field descriptor. + * \param has + * Whether the field is set. + * \param member + * The element to be packed. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes serialised to `buffer`. + */ static size_t optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean *has, @@ -1152,6 +1486,18 @@ optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, return required_field_pack_to_buffer(field, member, buffer); } +/** + * Get the packed size of an array of same field type. + * + * \param field + * Field descriptor. + * \param count + * Number of elements of this type. + * \param array + * The elements to get the size of. + * \return + * Number of bytes required. + */ static size_t get_packed_payload_length(const ProtobufCFieldDescriptor *field, unsigned count, const void *array) @@ -1203,11 +1549,25 @@ get_packed_payload_length(const ProtobufCFieldDescriptor *field, case PROTOBUF_C_TYPE_BOOL: return count; default: - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); } return rv; } +/** + * Pack an array of same field type to a virtual buffer. + * + * \param field + * Field descriptor. + * \param count + * Number of elements of this type. + * \param array + * The elements to get the size of. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes packed. + */ static size_t pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, unsigned count, const void *array, @@ -1230,8 +1590,8 @@ pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, buffer->append(buffer, len, scratch); rv += len; } -#endif break; +#endif case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: @@ -1291,7 +1651,7 @@ pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, } return count; default: - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); } return rv; @@ -1309,7 +1669,7 @@ repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, if (count == 0) return 0; - if (field->packed) { + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; size_t rv = tag_pack(field->id, scratch); size_t payload_len = get_packed_payload_length(field, count, array); @@ -1349,6 +1709,8 @@ unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, return rv + field->len; } +/**@}*/ + size_t protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, ProtobufCBuffer *buffer) @@ -1389,7 +1751,14 @@ protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, return rv; } -/* === unpacking === */ +/** + * \defgroup unpack unpacking implementation + * + * Routines mainly used by the unpacking functions. + * + * \ingroup internal + * @{ + */ static inline int int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value) @@ -1464,13 +1833,14 @@ parse_tag_and_wiretype(size_t len, /* sizeof(ScannedMember) must be <= (1<data; @@ -1624,7 +2002,8 @@ merge_messages(ProtobufCMessage *earlier_msg, (d_bd != NULL && l_data == d_bd->data)); break; - case PROTOBUF_C_TYPE_STRING: + } + case PROTOBUF_C_TYPE_STRING: { el_size = sizeof(char *); char *e_str = *(char **) earlier_elem; char *l_str = *(char **) latter_elem; @@ -1632,7 +2011,8 @@ merge_messages(ProtobufCMessage *earlier_msg, need_to_merge = e_str != d_str && l_str == d_str; break; - default: + } + default: { el_size = sizeof_elt_in_repeated_array(fields[i].type); need_to_merge = @@ -1644,6 +2024,7 @@ merge_messages(ProtobufCMessage *earlier_msg, fields[i].quantifier_offset); break; } + } if (need_to_merge) { memcpy(latter_elem, earlier_elem, el_size); @@ -1661,23 +2042,26 @@ merge_messages(ProtobufCMessage *earlier_msg, STRUCT_MEMBER(protobuf_c_boolean, latter_msg, fields[i]. - quantifier_offset) = 1; + quantifier_offset) = TRUE; STRUCT_MEMBER(protobuf_c_boolean, earlier_msg, fields[i]. - quantifier_offset) = 0; + quantifier_offset) = FALSE; } } } } - return 1; + return TRUE; } -/* - * Given a raw slab of packed-repeated values, determine the number of elements. - * This function detects certain kinds of errors but not others; the remaining - * error checking is done by parse_packed_repeated_member(). -*/ +/** + * Count packed elements. + * + * Given a raw slab of packed-repeated values, determine the number of + * elements. This function detects certain kinds of errors but not + * others; the remaining error checking is done by + * parse_packed_repeated_member(). + */ static protobuf_c_boolean count_packed_elements(ProtobufCType type, size_t len, const uint8_t *data, size_t *count_out) @@ -1818,8 +2202,8 @@ parse_boolean(unsigned len, const uint8_t *data) unsigned i; for (i = 0; i < len; i++) if (data[i] & 0x7f) - return 1; - return 0; + return TRUE; + return FALSE; } static protobuf_c_boolean @@ -1835,58 +2219,58 @@ parse_required_member(ScannedMember *scanned_member, switch (scanned_member->field->type) { case PROTOBUF_C_TYPE_INT32: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return 0; + return FALSE; *(uint32_t *) member = parse_int32(len, data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_UINT32: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return 0; + return FALSE; *(uint32_t *) member = parse_uint32(len, data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_SINT32: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return 0; + return FALSE; *(int32_t *) member = unzigzag32(parse_uint32(len, data)); - return 1; + return TRUE; case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) - return 0; + return FALSE; *(uint32_t *) member = parse_fixed_uint32(data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return 0; + return FALSE; *(uint64_t *) member = parse_uint64(len, data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_SINT64: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return 0; + return FALSE; *(int64_t *) member = unzigzag64(parse_uint64(len, data)); - return 1; + return TRUE; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) - return 0; + return FALSE; *(uint64_t *) member = parse_fixed_uint64(data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_BOOL: *(protobuf_c_boolean *) member = parse_boolean(len, data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_ENUM: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return 0; + return FALSE; *(uint32_t *) member = parse_uint32(len, data); - return 1; + return TRUE; case PROTOBUF_C_TYPE_STRING: { char **pstr = member; unsigned pref_len = scanned_member->length_prefix_len; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return 0; + return FALSE; if (maybe_clear && *pstr != NULL) { const char *def = scanned_member->field->default_value; @@ -1895,10 +2279,10 @@ parse_required_member(ScannedMember *scanned_member, } *pstr = do_alloc(allocator, len - pref_len + 1); if (*pstr == NULL) - return 0; + return FALSE; memcpy(*pstr, data + pref_len, len - pref_len); (*pstr)[len - pref_len] = 0; - return 1; + return TRUE; } case PROTOBUF_C_TYPE_BYTES: { ProtobufCBinaryData *bd = member; @@ -1906,7 +2290,7 @@ parse_required_member(ScannedMember *scanned_member, unsigned pref_len = scanned_member->length_prefix_len; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return 0; + return FALSE; def_bd = scanned_member->field->default_value; if (maybe_clear && @@ -1918,22 +2302,21 @@ parse_required_member(ScannedMember *scanned_member, if (len - pref_len > 0) { bd->data = do_alloc(allocator, len - pref_len); if (bd->data == NULL) - return 0; + return FALSE; memcpy(bd->data, data + pref_len, len - pref_len); } bd->len = len - pref_len; - return 1; + return TRUE; } - //case PROTOBUF_C_TYPE_GROUP: // NOT SUPPORTED case PROTOBUF_C_TYPE_MESSAGE: { ProtobufCMessage **pmessage = member; ProtobufCMessage *subm; const ProtobufCMessage *def_mess; - protobuf_c_boolean merge_successful = 1; + protobuf_c_boolean merge_successful = TRUE; unsigned pref_len = scanned_member->length_prefix_len; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return 0; + return FALSE; def_mess = scanned_member->field->default_value; subm = protobuf_c_message_unpack(scanned_member->field->descriptor, @@ -1952,11 +2335,11 @@ parse_required_member(ScannedMember *scanned_member, } *pmessage = subm; if (subm == NULL || !merge_successful) - return 0; - return 1; + return FALSE; + return TRUE; } } - return 0; + return FALSE; } static protobuf_c_boolean @@ -1966,12 +2349,12 @@ parse_optional_member(ScannedMember *scanned_member, ProtobufCAllocator *allocator) { if (!parse_required_member(scanned_member, member, allocator, TRUE)) - return 0; + return FALSE; if (scanned_member->field->quantifier_offset != 0) STRUCT_MEMBER(protobuf_c_boolean, message, - scanned_member->field->quantifier_offset) = 1; - return 1; + scanned_member->field->quantifier_offset) = TRUE; + return TRUE; } static protobuf_c_boolean @@ -1988,10 +2371,10 @@ parse_repeated_member(ScannedMember *scanned_member, if (!parse_required_member(scanned_member, array + siz * (*p_n), allocator, FALSE)) { - return 0; + return FALSE; } *p_n += 1; - return 1; + return TRUE; } static unsigned @@ -2016,7 +2399,7 @@ parse_packed_repeated_member(ScannedMember *scanned_member, const ProtobufCFieldDescriptor *field = scanned_member->field; size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); size_t siz = sizeof_elt_in_repeated_array(field->type); - char *array = *(char **) member + siz * (*p_n); + void *array = *(void **) member + siz * (*p_n); const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len; size_t rem = scanned_member->len - scanned_member->length_prefix_len; size_t count = 0; @@ -2034,8 +2417,8 @@ parse_packed_repeated_member(ScannedMember *scanned_member, ((uint32_t *) array)[i] = parse_fixed_uint32(at); at += 4; } -#endif break; +#endif case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: @@ -2123,7 +2506,7 @@ parse_packed_repeated_member(ScannedMember *scanned_member, } break; default: - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); } *p_n += count; return TRUE; @@ -2162,9 +2545,9 @@ parse_member(ScannedMember *scanned_member, ufield->len = scanned_member->len; ufield->data = do_alloc(allocator, scanned_member->len); if (ufield->data == NULL) - return 0; + return FALSE; memcpy(ufield->data, scanned_member->data, ufield->len); - return 1; + return TRUE; } member = (char *) message + field->offset; switch (field->label) { @@ -2177,7 +2560,8 @@ parse_member(ScannedMember *scanned_member, case PROTOBUF_C_LABEL_REPEATED: if (scanned_member->wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && - (field->packed || is_packable_type(field->type))) + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || + is_packable_type(field->type))) { return parse_packed_repeated_member(scanned_member, member, message); @@ -2187,18 +2571,20 @@ parse_member(ScannedMember *scanned_member, allocator); } } - PROTOBUF_C_ASSERT_NOT_REACHED(); + PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } -/* - * TODO: expose/use this function if desc->message_init == NULL (which occurs - * for old code, and may be useful for certain programmatic techniques for - * generating descriptors). +/** + * Initialise messages generated by old code. + * + * This function is used if desc->message_init == NULL (which occurs + * for old code, and which would be useful to support allocating + * descriptors dynamically). */ -void -protobuf_c_message_init_generic(const ProtobufCMessageDescriptor *desc, - ProtobufCMessage *message) +static void +message_init_generic(const ProtobufCMessageDescriptor *desc, + ProtobufCMessage *message) { unsigned i; @@ -2250,6 +2636,8 @@ protobuf_c_message_init_generic(const ProtobufCMessageDescriptor *desc, } } +/**@}*/ + /* * ScannedMember slabs (an unpacking implementation detail). Before doing real * unpacking, we first scan through the elements to see how many there are (for @@ -2271,6 +2659,12 @@ protobuf_c_message_init_generic(const ProtobufCMessageDescriptor *desc, - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2) +#define REQUIRED_FIELD_BITMAP_SET(index) \ + (required_fields_bitmap[(index)/8] |= (1<<((index)%8))) + +#define REQUIRED_FIELD_BITMAP_IS_SET(index) \ + (required_fields_bitmap[(index)/8] & (1<<((index)%8))) + ProtobufCMessage * protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, ProtobufCAllocator *allocator, @@ -2297,25 +2691,32 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, unsigned j; unsigned i_slab; unsigned last_field_index = 0; - unsigned char required_fields_bitmap[MAX_MEMBERS_FOR_HASH_SIZE / 8] = - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; + unsigned required_fields_bitmap_len; + unsigned char required_fields_bitmap_stack[16]; + unsigned char *required_fields_bitmap = required_fields_bitmap_stack; + protobuf_c_boolean required_fields_bitmap_alloced = FALSE; ASSERT_IS_MESSAGE_DESCRIPTOR(desc); if (allocator == NULL) - allocator = &protobuf_c_default_allocator; - - /* We treat all fields % (16*8), which should be good enough. */ -#define REQUIRED_FIELD_BITMAP_SET(index) \ - (required_fields_bitmap[(index/8)%sizeof(required_fields_bitmap)] |= (1<<((index)%8))) -#define REQUIRED_FIELD_BITMAP_IS_SET(index) \ - (required_fields_bitmap[(index/8)%sizeof(required_fields_bitmap)] & (1<<((index)%8))) + allocator = &protobuf_c__allocator; rv = do_alloc(allocator, desc->sizeof_message); if (!rv) return (NULL); scanned_member_slabs[0] = first_member_slab; + required_fields_bitmap_len = (desc->n_fields + 7) / 8; + if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) { + required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len); + if (!required_fields_bitmap) { + do_free(allocator, rv); + return (NULL); + } + required_fields_bitmap_alloced = TRUE; + } + memset(required_fields_bitmap, 0, required_fields_bitmap_len); + /* * Generated code always defines "message_init". However, we provide a * fallback for (1) users of old protobuf-c generated-code that do not @@ -2325,7 +2726,7 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, if (desc->message_init != NULL) protobuf_c_message_init(desc, rv); else - protobuf_c_message_init_generic(desc, rv); + message_init_generic(desc, rv); while (rem > 0) { uint32_t tag; @@ -2339,7 +2740,10 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, (unsigned) (at - data)); goto error_cleanup_during_scan; } - /* XXX: consider optimizing for field[1].id == tag, if field[1] exists! */ + /* + * \todo Consider optimizing for field[1].id == tag, if field[1] + * exists! + */ if (last_field == NULL || last_field->id != tag) { /* lookup field */ int field_index = @@ -2441,7 +2845,8 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, size_t *n = STRUCT_MEMBER_PTR(size_t, rv, field->quantifier_offset); if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && - (field->packed || is_packable_type(field->type))) + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || + is_packable_type(field->type))) { size_t count; if (!count_packed_elements(field->type, @@ -2532,24 +2937,27 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, /* cleanup */ for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]); - + if (required_fields_bitmap_alloced) + do_free(allocator, required_fields_bitmap); return rv; error_cleanup: protobuf_c_message_free_unpacked(rv, allocator); for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]); + if (required_fields_bitmap_alloced) + do_free(allocator, required_fields_bitmap); return NULL; error_cleanup_during_scan: do_free(allocator, rv); for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]); + if (required_fields_bitmap_alloced) + do_free(allocator, required_fields_bitmap); return NULL; } -/* === protobuf_c_message_free_unpacked() implementation === */ - void protobuf_c_message_free_unpacked(ProtobufCMessage *message, ProtobufCAllocator *allocator) @@ -2559,7 +2967,7 @@ protobuf_c_message_free_unpacked(ProtobufCMessage *message, ASSERT_IS_MESSAGE(message); if (allocator == NULL) - allocator = &protobuf_c_default_allocator; + allocator = &protobuf_c__allocator; message->descriptor = NULL; for (f = 0; f < desc->n_fields; f++) { if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { @@ -2636,48 +3044,71 @@ protobuf_c_message_check(const ProtobufCMessage *message) { if (!message || !message->descriptor || - message->descriptor->magic != PROTOBUF_C_MESSAGE_DESCRIPTOR_MAGIC) + message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { return FALSE; } - unsigned f; - for (f = 0; f < message->descriptor->n_fields; f++) { - ProtobufCType type = message->descriptor->fields[f].type; - ProtobufCLabel label = message->descriptor->fields[f].label; - if (type == PROTOBUF_C_TYPE_MESSAGE) { - unsigned offset = message->descriptor->fields[f].offset; - if (label == PROTOBUF_C_LABEL_REQUIRED) { - ProtobufCMessage *sub = *(ProtobufCMessage **) - ((char *) message + offset); - if (sub == NULL) - return FALSE; - if (!protobuf_c_message_check(sub)) - return FALSE; - } else if (label == PROTOBUF_C_LABEL_OPTIONAL) { - ProtobufCMessage *sub = *(ProtobufCMessage **) - ((char *) message + offset); - if (sub != NULL && !protobuf_c_message_check(sub)) - return FALSE; - } else if (label == PROTOBUF_C_LABEL_REPEATED) { - unsigned n = *(unsigned *) ((char *) message + - message->descriptor->fields[f].quantifier_offset); - ProtobufCMessage **subs = *(ProtobufCMessage ***) - ((char *) message + offset); - unsigned i; - for (i = 0; i < n; i++) - if (!protobuf_c_message_check(subs[i])) - return FALSE; + unsigned i; + for (i = 0; i < message->descriptor->n_fields; i++) { + const ProtobufCFieldDescriptor *f = message->descriptor->fields + i; + ProtobufCType type = f->type; + ProtobufCLabel label = f->label; + void *field = STRUCT_MEMBER_P (message, f->offset); + + if (label == PROTOBUF_C_LABEL_REPEATED) { + size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset); + + if (*quantity > 0 && *(void **) field == NULL) { + return FALSE; } - } else if (type == PROTOBUF_C_TYPE_STRING) { - if (label == PROTOBUF_C_LABEL_REQUIRED) { - char *str = *(char **) ((char *) - message + message->descriptor->fields[f].offset); - if (str == NULL) + + if (type == PROTOBUF_C_TYPE_MESSAGE) { + ProtobufCMessage **submessage = *(ProtobufCMessage ***) field; + unsigned j; + for (j = 0; j < *quantity; j++) { + if (!protobuf_c_message_check(submessage[j])) + return FALSE; + } + } else if (type == PROTOBUF_C_TYPE_STRING) { + char **string = *(char ***) field; + unsigned j; + for (j = 0; j < *quantity; j++) { + if (!string[j]) + return FALSE; + } + } else if (type == PROTOBUF_C_TYPE_BYTES) { + ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field; + unsigned j; + for (j = 0; j < *quantity; j++) { + if (bd[j].len > 0 && bd[j].data == NULL) + return FALSE; + } + } + + } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */ + + if (type == PROTOBUF_C_TYPE_MESSAGE) { + ProtobufCMessage *submessage = *(ProtobufCMessage **) field; + if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) { + if (!protobuf_c_message_check(submessage)) + return FALSE; + } + } else if (type == PROTOBUF_C_TYPE_STRING) { + char *string = *(char **) field; + if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL) return FALSE; + } else if (type == PROTOBUF_C_TYPE_BYTES) { + protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset); + ProtobufCBinaryData *bd = field; + if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) { + if (bd->len > 0 && bd->data == NULL) + return FALSE; + } } } } + return TRUE; } @@ -2698,11 +3129,11 @@ protobuf_c_service_invoke_internal(ProtobufCService *service, GenericHandler handler; /* - * Verify that method_index is within range. If this fails, you are - * likely invoking a newly added method on an old service. (Although + * Verify that method_index is within range. If this fails, you are + * likely invoking a newly added method on an old service. (Although * other memory corruption bugs can cause this assertion too.) - */ - PROTOBUF_C_ASSERT(method_index < service->descriptor->n_methods); + */ + assert(method_index < service->descriptor->n_methods); /* * Get the array of virtual methods (which are enumerated by the @@ -2710,8 +3141,10 @@ protobuf_c_service_invoke_internal(ProtobufCService *service, */ handlers = (GenericHandler *) (service + 1); - /* Get our method and invoke it. */ - /* TODO: seems like handler==NULL is a situation that needs handling. */ + /* + * Get our method and invoke it. + * \todo Seems like handler == NULL is a situation that needs handling. + */ handler = handlers[method_index]; (*handler)(service, input, closure, closure_data); } diff --git a/src/protobuf/google/protobuf-c/protobuf-c.h b/src/protobuf/google/protobuf-c/protobuf-c.h index 3e783d33..593df2d6 100644 --- a/src/protobuf/google/protobuf-c/protobuf-c.h +++ b/src/protobuf/google/protobuf-c/protobuf-c.h @@ -1,7 +1,6 @@ -/* --- protobuf-c.h: protobuf c runtime api --- */ - /* - * Copyright (c) 2008-2013, Dave Benson. All rights reserved. + * Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,486 +27,576 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __PROTOBUF_C_RUNTIME_H_ -#define __PROTOBUF_C_RUNTIME_H_ +/*! \file + * \mainpage Introduction + * + * This is [protobuf-c], a C implementation of [Protocol Buffers]. + * + * This file defines the public API for the `libprotobuf-c` support library. + * This API includes interfaces that can be used directly by client code as well + * as the interfaces used by the code generated by the `protoc-c` compiler. + * + * The `libprotobuf-c` support library performs the actual serialization and + * deserialization of Protocol Buffers messages. It interacts with structures, + * definitions, and metadata generated by the `protoc-c` compiler from .proto + * files. + * + * \authors Dave Benson and the `protobuf-c` authors. + * + * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. + * + * [protobuf-c]: https://github.com/protobuf-c/protobuf-c + * [Protocol Buffers]: https://developers.google.com/protocol-buffers/ + * [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause + * + * \page gencode Generated Code + * + * For each enum, we generate a C enum. For each message, we generate a C + * structure which can be cast to a `ProtobufCMessage`. + * + * For each enum and message, we generate a descriptor object that allows us to + * implement a kind of reflection on the structures. + * + * First, some naming conventions: + * + * - The name of the type for enums and messages and services is camel case + * (meaning WordsAreCrammedTogether) except that double underscores are used + * to delimit scopes. For example, the following `.proto` file: + * +~~~{.proto} + package foo.bar; + message BazBah { + optional int32 val = 1; + } +~~~ + * + * would generate a C type `Foo__Bar__BazBah`. + * + * - Identifiers for functions and globals are all lowercase, with camel case + * words separated by single underscores. For example, one of the function + * prototypes generated by `protoc-c` for the above example: + * +~~~{.c} +Foo__Bar__BazBah * + foo__bar__baz_bah__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +~~~ + * + * - Identifiers for enum values contain an uppercase prefix which embeds the + * package name and the enum type name. + * + * - A double underscore is used to separate further components of identifier + * names. + * + * For example, in the name of the unpack function above, the package name + * `foo.bar` has become `foo__bar`, the message name BazBah has become + * `baz_bah`, and the method name is `unpack`. These are all joined with double + * underscores to form the C identifier `foo__bar__baz_bah__unpack`. + * + * We also generate descriptor objects for messages and enums. These are + * declared in the `.pb-c.h` files: + * +~~~{.c} +extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor; +~~~ + * + * The message structures all begin with `ProtobufCMessageDescriptor *` which is + * sufficient to allow them to be cast to `ProtobufCMessage`. + * + * For each message defined in a `.proto` file, we generate a number of + * functions. Each function name contains a prefix based on the package name and + * message name in order to make it a unique C identifier. + * + * - `unpack()`. Unpacks data for a particular message format. Note that the + * `allocator` parameter is usually `NULL` to indicate that the system's + * `malloc()` and `free()` functions should be used for dynamically allocating + * memory. + * +~~~{.c} +Foo__Bar__BazBah * + foo__bar__baz_bah__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +~~~ + * + * - `free_unpacked()`. Frees a message object obtained with the `unpack()` + * method. + * +~~~{.c} +void foo__bar__baz_bah__free_unpacked + (Foo__Bar__BazBah *message, + ProtobufCAllocator *allocator); +~~~ + * + * - `get_packed_size()`. Calculates the length in bytes of the serialized + * representation of the message object. + * +~~~{.c} +size_t foo__bar__baz_bah__get_packed_size + (const Foo__Bar__BazBah *message); +~~~ + * + * - `pack()`. Pack a message object into a preallocated buffer. Assumes that + * the buffer is large enough. (Use `get_packed_size()` first.) + * +~~~{.c} +size_t foo__bar__baz_bah__pack + (const Foo__Bar__BazBah *message, + uint8_t *out); +~~~ + * + * - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an + * object which defines an "append bytes" callback to consume data as it is + * serialized. + * +~~~{.c} +size_t foo__bar__baz_bah__pack_to_buffer + (const Foo__Bar__BazBah *message, + ProtobufCBuffer *buffer); +~~~ + * + * \page pack Packing and unpacking messages + * + * To pack a message, first compute the packed size of the message with + * protobuf_c_message_get_packed_size(), then allocate a buffer of at least + * that size, then call protobuf_c_message_pack(). + * + * Alternatively, a message can be serialized without calculating the final size + * first. Use the protobuf_c_message_pack_to_buffer() function and provide a + * ProtobufCBuffer object which implements an "append" method that consumes + * data. + * + * To unpack a message, call the protobuf_c_message_unpack() function. The + * result can be cast to an object of the type that matches the descriptor for + * the message. + * + * The result of unpacking a message should be freed with + * protobuf_c_message_free_unpacked(). + */ + +#ifndef PROTOBUF_C_H +#define PROTOBUF_C_H #include +#include #include #include -#include #ifdef __cplusplus -# define PROTOBUF_C_BEGIN_DECLS extern "C" { -# define PROTOBUF_C_END_DECLS } +# define PROTOBUF_C__BEGIN_DECLS extern "C" { +# define PROTOBUF_C__END_DECLS } #else -# define PROTOBUF_C_BEGIN_DECLS -# define PROTOBUF_C_END_DECLS +# define PROTOBUF_C__BEGIN_DECLS +# define PROTOBUF_C__END_DECLS #endif -#define PROTOBUF_C_ASSERT(condition) assert(condition) -#define PROTOBUF_C_ASSERT_NOT_REACHED() assert(0) - -#if !defined(PROTOBUF_C_NO_DEPRECATED) -# if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) -# define PROTOBUF_C_DEPRECATED __attribute__((__deprecated__)) -# endif -#else -# define PROTOBUF_C_DEPRECATED -#endif - -#define PROTOBUF_C_OFFSETOF(struct, member) offsetof(struct, member) - -/* The version of protobuf-c you are compiling against. */ -#define PROTOBUF_C_MAJOR 0 -#define PROTOBUF_C_MINOR 16 - -/* The version of protobuf-c you are linking against. */ -extern unsigned protobuf_c_major; -extern unsigned protobuf_c_minor; +PROTOBUF_C__BEGIN_DECLS #if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) # ifdef PROTOBUF_C_EXPORT -# define PROTOBUF_C_API __declspec(dllexport) +# define PROTOBUF_C__API __declspec(dllexport) # else -# define PROTOBUF_C_API __declspec(dllimport) +# define PROTOBUF_C__API __declspec(dllimport) # endif #else -# define PROTOBUF_C_API +# define PROTOBUF_C__API #endif -PROTOBUF_C_BEGIN_DECLS +#if !defined(PROTOBUF_C__NO_DEPRECATED) +# if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__)) +# endif +#else +# define PROTOBUF_C__DEPRECATED +#endif -typedef int protobuf_c_boolean; +#ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE + #define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ + , _##enum_name##_IS_INT_SIZE = INT_MAX +#endif +#define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 +#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 +#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af + +/** + * \defgroup api Public API + * + * This is the public API for `libprotobuf-c`. These interfaces are stable and + * subject to Semantic Versioning guarantees. + * + * @{ + */ + +/** + * Values for the `flags` word in `ProtobufCFieldDescriptor`. + */ typedef enum { + /** Set if the field is repeated and marked with the `packed` option. */ + PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0), + + /** Set if the field is marked with the `deprecated` option. */ + PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1), +} ProtobufCFieldFlag; + +/** + * Message field rules. + * + * \see [Defining A Message Type] in the Protocol Buffers documentation. + * + * [Defining A Message Type]: + * https://developers.google.com/protocol-buffers/docs/proto#simple + */ +typedef enum { + /** A well-formed message must have exactly one of this field. */ PROTOBUF_C_LABEL_REQUIRED, + + /** + * A well-formed message can have zero or one of this field (but not + * more than one). + */ PROTOBUF_C_LABEL_OPTIONAL, - PROTOBUF_C_LABEL_REPEATED + + /** + * This field can be repeated any number of times (including zero) in a + * well-formed message. The order of the repeated values will be + * preserved. + */ + PROTOBUF_C_LABEL_REPEATED, } ProtobufCLabel; +/** + * Field value types. + * + * \see [Scalar Value Types] in the Protocol Buffers documentation. + * + * [Scalar Value Types]: + * https://developers.google.com/protocol-buffers/docs/proto#scalar + */ typedef enum { - PROTOBUF_C_TYPE_INT32, - PROTOBUF_C_TYPE_SINT32, - PROTOBUF_C_TYPE_SFIXED32, - PROTOBUF_C_TYPE_INT64, - PROTOBUF_C_TYPE_SINT64, - PROTOBUF_C_TYPE_SFIXED64, - PROTOBUF_C_TYPE_UINT32, - PROTOBUF_C_TYPE_FIXED32, - PROTOBUF_C_TYPE_UINT64, - PROTOBUF_C_TYPE_FIXED64, - PROTOBUF_C_TYPE_FLOAT, - PROTOBUF_C_TYPE_DOUBLE, - PROTOBUF_C_TYPE_BOOL, - PROTOBUF_C_TYPE_ENUM, - PROTOBUF_C_TYPE_STRING, - PROTOBUF_C_TYPE_BYTES, - //PROTOBUF_C_TYPE_GROUP, // NOT SUPPORTED - PROTOBUF_C_TYPE_MESSAGE, + PROTOBUF_C_TYPE_INT32, /**< int32 */ + PROTOBUF_C_TYPE_SINT32, /**< signed int32 */ + PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */ + PROTOBUF_C_TYPE_INT64, /**< int64 */ + PROTOBUF_C_TYPE_SINT64, /**< signed int64 */ + PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */ + PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */ + PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */ + PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */ + PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */ + PROTOBUF_C_TYPE_FLOAT, /**< float */ + PROTOBUF_C_TYPE_DOUBLE, /**< double */ + PROTOBUF_C_TYPE_BOOL, /**< boolean */ + PROTOBUF_C_TYPE_ENUM, /**< enumerated type */ + PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */ + PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */ + PROTOBUF_C_TYPE_MESSAGE, /**< nested message */ } ProtobufCType; -typedef struct _ProtobufCBinaryData ProtobufCBinaryData; -struct _ProtobufCBinaryData { - size_t len; - uint8_t *data; -}; +/** + * Field wire types. + * + * \see [Message Structure] in the Protocol Buffers documentation. + * + * [Message Structure]: + * https://developers.google.com/protocol-buffers/docs/encoding#structure + */ +typedef enum { + PROTOBUF_C_WIRE_TYPE_VARINT = 0, + PROTOBUF_C_WIRE_TYPE_64BIT = 1, + PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2, + /* "Start group" and "end group" wire types are unsupported. */ + PROTOBUF_C_WIRE_TYPE_32BIT = 5, +} ProtobufCWireType; -typedef struct _ProtobufCIntRange ProtobufCIntRange; /* private */ +struct ProtobufCAllocator; +struct ProtobufCBinaryData; +struct ProtobufCBuffer; +struct ProtobufCBufferSimple; +struct ProtobufCEnumDescriptor; +struct ProtobufCEnumValue; +struct ProtobufCEnumValueIndex; +struct ProtobufCFieldDescriptor; +struct ProtobufCIntRange; +struct ProtobufCMessage; +struct ProtobufCMessageDescriptor; +struct ProtobufCMessageUnknownField; +struct ProtobufCMethodDescriptor; +struct ProtobufCService; +struct ProtobufCServiceDescriptor; -/* --- memory management --- */ -typedef struct _ProtobufCAllocator ProtobufCAllocator; -struct _ProtobufCAllocator -{ +typedef struct ProtobufCAllocator ProtobufCAllocator; +typedef struct ProtobufCBinaryData ProtobufCBinaryData; +typedef struct ProtobufCBuffer ProtobufCBuffer; +typedef struct ProtobufCBufferSimple ProtobufCBufferSimple; +typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor; +typedef struct ProtobufCEnumValue ProtobufCEnumValue; +typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex; +typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor; +typedef struct ProtobufCIntRange ProtobufCIntRange; +typedef struct ProtobufCMessage ProtobufCMessage; +typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor; +typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField; +typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor; +typedef struct ProtobufCService ProtobufCService; +typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor; + +/** Boolean type. */ +typedef int protobuf_c_boolean; + +typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); +typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); +typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); + +/** + * Structure for defining a custom memory allocator. + */ +struct ProtobufCAllocator { + /** Function to allocate memory. */ void *(*alloc)(void *allocator_data, size_t size); + + /** Function to free memory. */ void (*free)(void *allocator_data, void *pointer); + + /** Opaque pointer passed to `alloc` and `free` functions. */ void *allocator_data; }; -/* - * This is a configurable allocator. - * By default, it uses the system allocator (meaning malloc() and free()). - * This is typically changed to adapt to frameworks that provide - * some nonstandard allocation functions. +/** + * Structure for the protobuf `bytes` scalar type. * - * NOTE: you may modify this allocator. + * The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of + * bytes. It may contain embedded `NUL` characters and is not required to be + * `NUL`-terminated. */ -extern PROTOBUF_C_API ProtobufCAllocator protobuf_c_default_allocator; /* settable */ +struct ProtobufCBinaryData { + size_t len; /**< Number of bytes in the `data` field. */ + uint8_t *data; /**< Data bytes. */ +}; -/* --- append-only data buffer --- */ -typedef struct _ProtobufCBuffer ProtobufCBuffer; -struct _ProtobufCBuffer { +/** + * Structure for defining a virtual append-only buffer. Used by + * protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized + * bytes. + * + * `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to + * write to a `FILE` object: + * +~~~{.c} +typedef struct { + ProtobufCBuffer base; + FILE *fp; +} BufferAppendToFile; + +static void +my_buffer_file_append(ProtobufCBuffer *buffer, + size_t len, + const uint8_t *data) +{ + BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer; + fwrite(data, len, 1, file_buf->fp); // XXX: No error handling! +} +~~~ + * + * To use this new type of ProtobufCBuffer, it could be called as follows: + * +~~~{.c} +... +BufferAppendToFile tmp = {0}; +tmp.base.append = my_buffer_file_append; +tmp.fp = fp; +protobuf_c_message_pack_to_buffer(&message, &tmp); +... +~~~ + */ +struct ProtobufCBuffer { + /** Append function. Consumes the `len` bytes stored at `data`. */ void (*append)(ProtobufCBuffer *buffer, size_t len, const uint8_t *data); }; -/* --- enums --- */ - -typedef struct _ProtobufCEnumValue ProtobufCEnumValue; -typedef struct _ProtobufCEnumValueIndex ProtobufCEnumValueIndex; -typedef struct _ProtobufCEnumDescriptor ProtobufCEnumDescriptor; - -/* - * ProtobufCEnumValue: this represents a single value of an enumeration. - * 'name' is the string identifying this value, as given in the .proto file. - * 'c_name' is the full name of the C enumeration value. - * 'value' is the number assigned to this value, as given in the .proto file. +/** + * Simple buffer "subclass" of `ProtobufCBuffer`. + * + * A `ProtobufCBufferSimple` object is declared on the stack and uses a + * scratch buffer provided by the user for the initial allocation. It performs + * exponential resizing, using dynamically allocated memory. A + * `ProtobufCBufferSimple` object can be created and used as follows: + * +~~~{.c} +uint8_t pad[128]; +ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad); +ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple; +~~~ + * + * `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a + * message has been serialized to a `ProtobufCBufferSimple` object, the + * serialized data bytes can be accessed from the `.data` field. + * + * To free the memory allocated by a `ProtobufCBufferSimple` object, if any, + * call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example: + * +~~~{.c} +PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple); +~~~ + * + * \see PROTOBUF_C_BUFFER_SIMPLE_INIT + * \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR */ -struct _ProtobufCEnumValue { - const char *name; - const char *c_name; - int value; +struct ProtobufCBufferSimple { + /** "Base class". */ + ProtobufCBuffer base; + /** Number of bytes allocated in `data`. */ + size_t alloced; + /** Number of bytes currently stored in `data`. */ + size_t len; + /** Data bytes. */ + uint8_t *data; + /** Whether `data` must be freed. */ + protobuf_c_boolean must_free_data; + /** Allocator to use. May be NULL to indicate the system allocator. */ + ProtobufCAllocator *allocator; }; -/* - * ProtobufCEnumDescriptor: represents the enum as a whole, with all its values. - * - * 'magic' is a code we check to ensure that the api is used correctly. - * 'name' is the qualified name (e.g. "namespace.Type"). - * 'short_name' is the unqualified name ("Type"), as given in the .proto file. - * 'package_name' is the '.'-separated namespace - * 'n_values' is the number of distinct values. - * 'values' is the array of distinct values. - * 'n_value_names' number of named values (including aliases). - * 'value_names' are the named values (including aliases). - * - * The rest of the values are private essentially. - * - * See also: Use protobuf_c_enum_descriptor_get_value_by_name() - * and protobuf_c_enum_descriptor_get_value() to efficiently - * lookup values in the descriptor. +/** + * Describes an enumeration as a whole, with all of its values. */ -struct _ProtobufCEnumDescriptor { +struct ProtobufCEnumDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ uint32_t magic; + /** The qualified name (e.g., "namespace.Type"). */ const char *name; + /** The unqualified name as given in the .proto file (e.g., "Type"). */ const char *short_name; + /** Identifier used in generated C code. */ const char *c_name; + /** The dot-separated namespace. */ const char *package_name; - /* sorted by value */ + /** Number elements in `values`. */ unsigned n_values; + /** Array of distinct values, sorted by numeric value. */ const ProtobufCEnumValue *values; - /* sorted by name */ + /** Number of elements in `values_by_name`. */ unsigned n_value_names; + /** Array of named values, including aliases, sorted by name. */ const ProtobufCEnumValueIndex *values_by_name; - /* value-ranges, for faster lookups by number */ + /** Number of elements in `value_ranges`. */ unsigned n_value_ranges; + /** Value ranges, for faster lookups by numeric value. */ const ProtobufCIntRange *value_ranges; + /** Reserved for future use. */ void *reserved1; + /** Reserved for future use. */ void *reserved2; + /** Reserved for future use. */ void *reserved3; + /** Reserved for future use. */ void *reserved4; }; -/* --- messages --- */ - -typedef struct _ProtobufCMessageDescriptor ProtobufCMessageDescriptor; -typedef struct _ProtobufCFieldDescriptor ProtobufCFieldDescriptor; -typedef struct _ProtobufCMessage ProtobufCMessage; -typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); - -/* - * ProtobufCFieldDescriptor: description of a single field in a message. - * - * 'name' is the name of the field, as given in the .proto file. - * 'id' is the code representing the field, as given in the .proto file. - * 'label' is one of PROTOBUF_C_LABEL_{REQUIRED,OPTIONAL,REPEATED} - * 'type' is the type of field. - * 'quantifier_offset' is the offset in bytes into the message's C structure - * for this member's "has_MEMBER" field (for optional members) or - * "n_MEMBER" field (for repeated members). - * 'offset' is the offset in bytes into the message's C structure - * for the member itself. - * 'descriptor' is a pointer to a ProtobufC{Enum,Message}Descriptor - * if type is PROTOBUF_C_TYPE_{ENUM,MESSAGE} respectively, - * otherwise NULL. - * 'default_value' is a pointer to a default value for this field, - * where allowed. - * 'packed' is only for REPEATED fields (it is 0 otherwise); this is if - * the repeated fields is marked with the 'packed' options. +/** + * Represents a single value of an enumeration. */ -struct _ProtobufCFieldDescriptor { - const char *name; - uint32_t id; - ProtobufCLabel label; - ProtobufCType type; - unsigned quantifier_offset; - unsigned offset; - const void *descriptor; /* for MESSAGE and ENUM types */ - const void *default_value; /* can be NULL */ - protobuf_c_boolean packed; +struct ProtobufCEnumValue { + /** The string identifying this value in the .proto file. */ + const char *name; + /** The string identifying this value in generated C code. */ + const char *c_name; + + /** The numeric value assigned in the .proto file. */ + int value; +}; + +/** + * Used by `ProtobufCEnumDescriptor` to look up enum values. + */ +struct ProtobufCEnumValueIndex { + /** Name of the enum value. */ + const char *name; + /** Index into values[] array. */ + unsigned index; +}; + +/** + * Describes a single field in a message. + */ +struct ProtobufCFieldDescriptor { + /** Name of the field as given in the .proto file. */ + const char *name; + + /** Tag value of the field as given in the .proto file. */ + uint32_t id; + + /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ + ProtobufCLabel label; + + /** The type of the field. */ + ProtobufCType type; + + /** + * The offset in bytes of the message's C structure's quantifier field + * (the `has_MEMBER` field for optional members or the `n_MEMBER` field + * for repeated members. + */ + unsigned quantifier_offset; + + /** + * The offset in bytes into the message's C structure for the member + * itself. + */ + unsigned offset; + + /** + * A type-specific descriptor. + * + * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the + * corresponding `ProtobufCEnumDescriptor`. + * + * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to + * the corresponding `ProtobufCMessageDescriptor`. + * + * Otherwise this field is NULL. + */ + const void *descriptor; /* for MESSAGE and ENUM types */ + + /** The default value for this field, if defined. May be NULL. */ + const void *default_value; + + /** + * A flag word. Zero or more of the bits defined in the + * `ProtobufCFieldFlag` enum may be set. + */ + uint32_t flags; + + /** Reserved for future use. */ unsigned reserved_flags; + /** Reserved for future use. */ void *reserved2; + /** Reserved for future use. */ void *reserved3; }; -/* - * ProtobufCMessageDescriptor: description of a message. - * - * 'magic' is a code we check to ensure that the api is used correctly. - * 'name' is the qualified name (e.g. "namespace.Type"). - * 'short_name' is the unqualified name ("Type"), as given in the .proto file. - * 'c_name' is the c-formatted name of the structure - * 'package_name' is the '.'-separated namespace - * 'sizeof_message' is the size in bytes of the C structure - * representing an instance of this type of message. - * 'n_fields' is the number of known fields in this message. - * 'fields' is the fields sorted by id number. - * 'fields_sorted_by_name', 'n_field_ranges' and 'field_ranges' - * are used for looking up fields by name and id. (private) - */ -struct _ProtobufCMessageDescriptor { - uint32_t magic; - - const char *name; - const char *short_name; - const char *c_name; - const char *package_name; - - size_t sizeof_message; - - /* sorted by field-id */ - unsigned n_fields; - const ProtobufCFieldDescriptor *fields; - const unsigned *fields_sorted_by_name; - - /* ranges, optimization for looking up fields */ - unsigned n_field_ranges; - const ProtobufCIntRange *field_ranges; - - ProtobufCMessageInit message_init; - void *reserved1; - void *reserved2; - void *reserved3; -}; - -/* - * ProtobufCMessage: an instance of a message. - * - * ProtobufCMessage is sort of a light-weight base class for all messages. - * - * In particular, ProtobufCMessage doesn't have any allocation policy - * associated with it. That's because it's common to create ProtobufCMessage's - * on the stack. In fact, that's what we recommend for sending messages - * (because if you just allocate from the stack, then you can't really have a - * memory leak). - * - * This means that functions like protobuf_c_message_unpack() which return a - * ProtobufCMessage must be paired with a free function, like - * protobuf_c_message_free_unpacked(). - * - * 'descriptor' gives the locations and types of the members of message. - * 'n_unknown_fields' is the number of fields we didn't recognize. - * 'unknown_fields' are fields we didn't recognize. - */ -typedef struct _ProtobufCMessageUnknownField ProtobufCMessageUnknownField; -struct _ProtobufCMessage { - const ProtobufCMessageDescriptor *descriptor; - unsigned n_unknown_fields; - ProtobufCMessageUnknownField *unknown_fields; -}; - -#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } - -/* - * To pack a message: you have two options: - * (1) you can compute the size of the message using - * protobuf_c_message_get_packed_size() then pass - * protobuf_c_message_pack() a buffer of that length. - * - * (2) Provide a virtual buffer (a ProtobufCBuffer) to - * accept data as we scan through it. - */ -PROTOBUF_C_API size_t -protobuf_c_message_get_packed_size(const ProtobufCMessage *); - -PROTOBUF_C_API size_t -protobuf_c_message_pack(const ProtobufCMessage *, uint8_t *out); - -PROTOBUF_C_API size_t -protobuf_c_message_pack_to_buffer(const ProtobufCMessage *, ProtobufCBuffer *); - -PROTOBUF_C_API ProtobufCMessage * -protobuf_c_message_unpack( - const ProtobufCMessageDescriptor *, - ProtobufCAllocator *, - size_t len, - const uint8_t *data); - -PROTOBUF_C_API void -protobuf_c_message_free_unpacked(ProtobufCMessage *, ProtobufCAllocator *); - -PROTOBUF_C_API protobuf_c_boolean -protobuf_c_message_check(const ProtobufCMessage *); - -/* - * WARNING: 'message' must be a block of memory of size - * descriptor->sizeof_message. - */ -PROTOBUF_C_API void -protobuf_c_message_init(const ProtobufCMessageDescriptor *, void *message); - -/* --- services --- */ - -typedef struct _ProtobufCMethodDescriptor ProtobufCMethodDescriptor; -struct _ProtobufCMethodDescriptor { - const char *name; - const ProtobufCMessageDescriptor *input; - const ProtobufCMessageDescriptor *output; -}; - -typedef struct _ProtobufCServiceDescriptor ProtobufCServiceDescriptor; -struct _ProtobufCServiceDescriptor { - uint32_t magic; - - const char *name; - const char *short_name; - const char *c_name; - const char *package; - unsigned n_methods; - const ProtobufCMethodDescriptor *methods; /* in order from .proto file */ - const unsigned *method_indices_by_name; -}; - -typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); - -typedef struct _ProtobufCService ProtobufCService; -struct _ProtobufCService { - const ProtobufCServiceDescriptor *descriptor; - void (*invoke)(ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); - void (*destroy)(ProtobufCService *service); -}; - -PROTOBUF_C_API void -protobuf_c_service_destroy(ProtobufCService *); - -/* --- querying the descriptors --- */ - -PROTOBUF_C_API const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value_by_name( - const ProtobufCEnumDescriptor *desc, - const char *name); - -PROTOBUF_C_API const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value( - const ProtobufCEnumDescriptor *desc, - int value); - -PROTOBUF_C_API const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field_by_name( - const ProtobufCMessageDescriptor *desc, - const char *name); - -PROTOBUF_C_API const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field( - const ProtobufCMessageDescriptor *desc, - unsigned value); - -PROTOBUF_C_API const ProtobufCMethodDescriptor * -protobuf_c_service_descriptor_get_method_by_name( - const ProtobufCServiceDescriptor *desc, - const char *name); - -/* --- wire format enums --- */ - -typedef enum { - PROTOBUF_C_WIRE_TYPE_VARINT, - PROTOBUF_C_WIRE_TYPE_64BIT, - PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED, - PROTOBUF_C_WIRE_TYPE_START_GROUP, /* unsupported */ - PROTOBUF_C_WIRE_TYPE_END_GROUP, /* unsupported */ - PROTOBUF_C_WIRE_TYPE_32BIT -} ProtobufCWireType; - -/* --- unknown message fields --- */ - -struct _ProtobufCMessageUnknownField { - uint32_t tag; - ProtobufCWireType wire_type; - size_t len; - uint8_t *data; -}; - -/* --- extra (superfluous) api: trivial buffer --- */ - -typedef struct _ProtobufCBufferSimple ProtobufCBufferSimple; -struct _ProtobufCBufferSimple { - ProtobufCBuffer base; - size_t alloced; - size_t len; - uint8_t *data; - protobuf_c_boolean must_free_data; -}; - -#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ -{ \ - { protobuf_c_buffer_simple_append }, \ - sizeof(array_of_bytes), \ - 0, \ - (array_of_bytes), \ - 0 \ -} - -#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ -do { \ - if ((simp_buf)->must_free_data) { \ - protobuf_c_default_allocator.free( \ - &protobuf_c_default_allocator, \ - (simp_buf)->data); \ - } \ -} while (0) - -/* ====== private ====== */ - -#define PROTOBUF_C_SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 -#define PROTOBUF_C_MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 -#define PROTOBUF_C_ENUM_DESCRIPTOR_MAGIC 0x114315af - -/* - * A little enum helper macro: this will ensure that your enum's size is - * sizeof(int). In protobuf, it need not be larger than 32-bits. This is - * written assuming it is appended to a list w/o a tail comma. - */ -#ifndef _PROTOBUF_C_FORCE_ENUM_TO_BE_INT_SIZE - #define _PROTOBUF_C_FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ - , _##enum_name##_IS_INT_SIZE = INT_MAX -#endif - -/* === needs to be declared for the PROTOBUF_C_BUFFER_SIMPLE_INIT macro === */ - -void -protobuf_c_buffer_simple_append( - ProtobufCBuffer *buffer, - size_t len, - const unsigned char *data); - -/* === stuff which needs to be declared for use in the generated code === */ - -struct _ProtobufCEnumValueIndex { - const char *name; - unsigned index; /* into values[] array */ -}; - -/* - * IntRange: helper structure for optimizing int => index lookups in the case +/** + * Helper structure for optimizing int => index lookups in the case * where the keys are mostly consecutive values, as they presumably are for * enums and fields. * - * The data structures assumes that the values in the original array are + * The data structures requires that the values in the original array are * sorted. */ -struct _ProtobufCIntRange { - int start_value; - unsigned orig_index; +struct ProtobufCIntRange { + int start_value; + unsigned orig_index; /* * NOTE: the number of values in the range can be inferred by looking * at the next element's orig_index. A dummy element is added to make @@ -515,27 +604,467 @@ struct _ProtobufCIntRange { */ }; -/* === declared for exposition on ProtobufCIntRange === */ - -/* - * Note: ranges must have an extra sentinel IntRange at the end whose - * orig_index is set to the number of actual values in the original array. - * Returns -1 if no orig_index found. +/** + * An instance of a message. + * + * `ProtobufCMessage` is a light-weight "base class" for all messages. + * + * In particular, `ProtobufCMessage` doesn't have any allocation policy + * associated with it. That's because it's common to create `ProtobufCMessage` + * objects on the stack. In fact, that's what we recommend for sending messages. + * If the object is allocated from the stack, you can't really have a memory + * leak. + * + * This means that calls to functions like protobuf_c_message_unpack() which + * return a `ProtobufCMessage` must be paired with a call to a free function, + * like protobuf_c_message_free_unpacked(). */ -int -protobuf_c_int_ranges_lookup(unsigned n_ranges, ProtobufCIntRange *ranges); +struct ProtobufCMessage { + /** The descriptor for this message type. */ + const ProtobufCMessageDescriptor *descriptor; + /** The number of elements in `unknown_fields`. */ + unsigned n_unknown_fields; + /** The fields that weren't recognized by the parser. */ + ProtobufCMessageUnknownField *unknown_fields; +}; -/* === behind the scenes on the generated service's __init functions */ +/** + * Describes a message. + */ +struct ProtobufCMessageDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; -typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); + /** The qualified name (e.g., "namespace.Type"). */ + const char *name; + /** The unqualified name as given in the .proto file (e.g., "Type"). */ + const char *short_name; + /** Identifier used in generated C code. */ + const char *c_name; + /** The dot-separated namespace. */ + const char *package_name; + /** + * Size in bytes of the C structure representing an instance of this + * type of message. + */ + size_t sizeof_message; + + /** Number of elements in `fields`. */ + unsigned n_fields; + /** Field descriptors, sorted by tag number. */ + const ProtobufCFieldDescriptor *fields; + /** Used for looking up fields by name. */ + const unsigned *fields_sorted_by_name; + + /** Number of elements in `field_ranges`. */ + unsigned n_field_ranges; + /** Used for looking up fields by id. */ + const ProtobufCIntRange *field_ranges; + + /** Message initialisation function. */ + ProtobufCMessageInit message_init; + + /** Reserved for future use. */ + void *reserved1; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; +}; + +/** + * An unknown message field. + */ +struct ProtobufCMessageUnknownField { + /** The tag number. */ + uint32_t tag; + /** The wire type of the field. */ + ProtobufCWireType wire_type; + /** Number of bytes in `data`. */ + size_t len; + /** Field data. */ + uint8_t *data; +}; + +/** + * Method descriptor. + */ +struct ProtobufCMethodDescriptor { + /** Method name. */ + const char *name; + /** Input message descriptor. */ + const ProtobufCMessageDescriptor *input; + /** Output message descriptor. */ + const ProtobufCMessageDescriptor *output; +}; + +/** + * Service. + */ +struct ProtobufCService { + /** Service descriptor. */ + const ProtobufCServiceDescriptor *descriptor; + /** Function to invoke the service. */ + void (*invoke)(ProtobufCService *service, + unsigned method_index, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data); + /** Function to destroy the service. */ + void (*destroy)(ProtobufCService *service); +}; + +/** + * Service descriptor. + */ +struct ProtobufCServiceDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** Service name. */ + const char *name; + /** Short version of service name. */ + const char *short_name; + /** C identifier for the service name. */ + const char *c_name; + /** Package name. */ + const char *package; + /** Number of elements in `methods`. */ + unsigned n_methods; + /** Method descriptors, in the order defined in the .proto file. */ + const ProtobufCMethodDescriptor *methods; + /** Sort index of methods. */ + const unsigned *method_indices_by_name; +}; + +/** + * Get the version of the protobuf-c library. Note that this is the version of + * the library linked against, not the version of the headers compiled against. + * + * \return A string containing the version number of protobuf-c. + */ +PROTOBUF_C__API +const char * +protobuf_c_version(void); + +/** + * Get the version of the protobuf-c library. Note that this is the version of + * the library linked against, not the version of the headers compiled against. + * + * \return A 32 bit unsigned integer containing the version number of + * protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH. + */ +PROTOBUF_C__API +uint32_t +protobuf_c_version_number(void); + +/** + * The version of the protobuf-c headers, represented as a string using the same + * format as protobuf_c_version(). + */ +#define PROTOBUF_C_VERSION "1.0.0" + +/** + * The version of the protobuf-c headers, represented as an integer using the + * same format as protobuf_c_version_number(). + */ +#define PROTOBUF_C_VERSION_NUMBER 1000000 + +/** + * The minimum protoc-c version which works with the current version of the + * protobuf-c headers. + */ +#define PROTOBUF_C_MIN_COMPILER_VERSION 1000000 + +/** + * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name. + * + * \param desc + * The `ProtobufCEnumDescriptor` object. + * \param name + * The `name` field from the corresponding `ProtobufCEnumValue` object to + * match. + * \return + * A `ProtobufCEnumValue` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value_by_name( + const ProtobufCEnumDescriptor *desc, + const char *name); + +/** + * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric + * value. + * + * \param desc + * The `ProtobufCEnumDescriptor` object. + * \param value + * The `value` field from the corresponding `ProtobufCEnumValue` object to + * match. + * + * \return + * A `ProtobufCEnumValue` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value( + const ProtobufCEnumDescriptor *desc, + int value); + +/** + * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by + * the name of the field. + * + * \param desc + * The `ProtobufCMessageDescriptor` object. + * \param name + * The name of the field. + * \return + * A `ProtobufCFieldDescriptor` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field_by_name( + const ProtobufCMessageDescriptor *desc, + const char *name); + +/** + * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by + * the tag value of the field. + * + * \param desc + * The `ProtobufCMessageDescriptor` object. + * \param value + * The tag value of the field. + * \return + * A `ProtobufCFieldDescriptor` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field( + const ProtobufCMessageDescriptor *desc, + unsigned value); + +/** + * Determine the number of bytes required to store the serialised message. + * + * \param message + * The message object to serialise. + * \return + * Number of bytes. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_get_packed_size(const ProtobufCMessage *message); + +/** + * Serialise a message from its in-memory representation. + * + * This function stores the serialised bytes of the message in a pre-allocated + * buffer. + * + * \param message + * The message object to serialise. + * \param[out] out + * Buffer to store the bytes of the serialised message. This buffer must + * have enough space to store the packed message. Use + * protobuf_c_message_get_packed_size() to determine the number of bytes + * required. + * \return + * Number of bytes stored in `out`. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out); + +/** + * Serialise a message from its in-memory representation to a virtual buffer. + * + * This function calls the `append` method of a `ProtobufCBuffer` object to + * consume the bytes generated by the serialiser. + * + * \param message + * The message object to serialise. + * \param buffer + * The virtual buffer object. + * \return + * Number of bytes passed to the virtual buffer. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_pack_to_buffer( + const ProtobufCMessage *message, + ProtobufCBuffer *buffer); + +/** + * Unpack a serialised message into an in-memory representation. + * + * \param descriptor + * The message descriptor. + * \param allocator + * `ProtobufCAllocator` to use for memory allocation. May be NULL to + * specify the default allocator. + * \param len + * Length in bytes of the serialised message. + * \param data + * Pointer to the serialised message. + * \return + * An unpacked message object. + * \retval NULL + * If an error occurred during unpacking. + */ +PROTOBUF_C__API +ProtobufCMessage * +protobuf_c_message_unpack( + const ProtobufCMessageDescriptor *descriptor, + ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); + +/** + * Free an unpacked message object. + * + * This function should be used to deallocate the memory used by a call to + * protobuf_c_message_unpack(). + * + * \param message + * The message object to free. + * \param allocator + * `ProtobufCAllocator` to use for memory deallocation. May be NULL to + * specify the default allocator. + */ +PROTOBUF_C__API +void +protobuf_c_message_free_unpacked( + ProtobufCMessage *message, + ProtobufCAllocator *allocator); + +/** + * Check the validity of a message object. + * + * Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present. + * Recursively checks nested messages. + * + * \retval TRUE + * Message is valid. + * \retval FALSE + * Message is invalid. + */ +PROTOBUF_C__API +protobuf_c_boolean +protobuf_c_message_check(const ProtobufCMessage *); + +/** Message initialiser. */ +#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } + +/** + * Initialise a message object from a message descriptor. + * + * \param descriptor + * Message descriptor. + * \param message + * Allocated block of memory of size `descriptor->sizeof_message`. + */ +PROTOBUF_C__API +void +protobuf_c_message_init( + const ProtobufCMessageDescriptor *descriptor, + void *message); + +/** + * Free a service. + * + * \param service + * The service object to free. + */ +PROTOBUF_C__API +void +protobuf_c_service_destroy(ProtobufCService *service); + +/** + * Look up a `ProtobufCMethodDescriptor` by name. + * + * \param desc + * Service descriptor. + * \param name + * Name of the method. + * + * \return + * A `ProtobufCMethodDescriptor` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCMethodDescriptor * +protobuf_c_service_descriptor_get_method_by_name( + const ProtobufCServiceDescriptor *desc, + const char *name); + +/** + * Initialise a `ProtobufCBufferSimple` object. + */ +#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ +{ \ + { protobuf_c_buffer_simple_append }, \ + sizeof(array_of_bytes), \ + 0, \ + (array_of_bytes), \ + 0, \ + NULL \ +} + +/** + * Clear a `ProtobufCBufferSimple` object, freeing any allocated memory. + */ +#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ +do { \ + if ((simp_buf)->must_free_data) { \ + if ((simp_buf)->allocator != NULL) \ + (simp_buf)->allocator->free( \ + (simp_buf)->allocator, \ + (simp_buf)->data); \ + else \ + free((simp_buf)->data); \ + } \ +} while (0) + +/** + * The `append` method for `ProtobufCBufferSimple`. + * + * \param buffer + * The buffer object to append to. Must actually be a + * `ProtobufCBufferSimple` object. + * \param len + * Number of bytes in `data`. + * \param data + * Data to append. + */ +PROTOBUF_C__API +void +protobuf_c_buffer_simple_append( + ProtobufCBuffer *buffer, + size_t len, + const unsigned char *data); + +PROTOBUF_C__API void protobuf_c_service_generated_init( ProtobufCService *service, const ProtobufCServiceDescriptor *descriptor, ProtobufCServiceDestroy destroy); -void +PROTOBUF_C__API +void protobuf_c_service_invoke_internal( ProtobufCService *service, unsigned method_index, @@ -543,6 +1072,8 @@ protobuf_c_service_invoke_internal( ProtobufCClosure closure, void *closure_data); -PROTOBUF_C_END_DECLS +/**@}*/ -#endif /* __PROTOBUF_C_RUNTIME_H_ */ +PROTOBUF_C__END_DECLS + +#endif /* PROTOBUF_C_H */