diff --git a/net/ocserv/Makefile b/net/ocserv/Makefile index 4a3055175..c850e498d 100644 --- a/net/ocserv/Makefile +++ b/net/ocserv/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ocserv -PKG_VERSION:=0.8.2 -PKG_RELEASE:=2 +PKG_VERSION:=0.8.3 +PKG_RELEASE:=1 PKG_BUILD_DIR :=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL :=ftp://ftp.infradead.org/pub/ocserv/ -PKG_MD5SUM:=fd890e121445dfe8bb514da67c91c675 +PKG_MD5SUM:=fd74a172a34a9b4e0d52a43b098adbec PKG_LICENSE:=GPLv3 PKG_LICENSE_FILES:=COPYING diff --git a/net/ocserv/patches/0001-corrected-included-protobuf-s-path-to-align-with-pro.patch b/net/ocserv/patches/0001-corrected-included-protobuf-s-path-to-align-with-pro.patch new file mode 100644 index 000000000..7de95f45a --- /dev/null +++ b/net/ocserv/patches/0001-corrected-included-protobuf-s-path-to-align-with-pro.patch @@ -0,0 +1,8774 @@ +From 60bea96ccef5589bd8d35a438fdb9b3759852f36 Mon Sep 17 00:00:00 2001 +From: Nikos Mavrogiannopoulos +Date: Sun, 24 Aug 2014 08:14:11 +0200 +Subject: [PATCH] corrected included protobuf's path, to align with protobuf + 1.0.0 + +--- + configure.ac | 2 +- + src/Makefile.am | 2 +- + src/protobuf/google/protobuf-c/protobuf-c.c | 3272 --------------------------- + src/protobuf/google/protobuf-c/protobuf-c.h | 1079 --------- + src/protobuf/protobuf-c/protobuf-c.c | 3272 +++++++++++++++++++++++++++ + src/protobuf/protobuf-c/protobuf-c.h | 1079 +++++++++ + 6 files changed, 4353 insertions(+), 4353 deletions(-) + delete mode 100644 src/protobuf/google/protobuf-c/protobuf-c.c + delete mode 100644 src/protobuf/google/protobuf-c/protobuf-c.h + create mode 100644 src/protobuf/protobuf-c/protobuf-c.c + create mode 100644 src/protobuf/protobuf-c/protobuf-c.h + +diff --git a/configure.ac b/configure.ac +index 0515053..403fc45 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -78,7 +78,7 @@ if test "$test_for_protobuf" = yes;then + PKG_CHECK_MODULES([LIBPROTOBUF_C], [libprotobuf-c], + with_local_protobuf_c=no + , +-[AC_LIB_HAVE_LINKFLAGS(protobuf-c,, [#include ], [protobuf_c_message_pack(0,0);]) ++[AC_LIB_HAVE_LINKFLAGS(protobuf-c,, [#include ], [protobuf_c_message_pack(0,0);]) + if test x$ac_cv_libprotobuf_c = xyes; then + AC_SUBST([LIBPROTOBUF_C_LIBS], [$LIBPROTOBUF_C]) + with_local_protobuf_c=no +diff --git a/src/Makefile.am b/src/Makefile.am +index 74acda4..69d3185 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -55,7 +55,7 @@ ocserv-args.h: ocserv-args.c + + PROTOBUF_SOURCES = + if LOCAL_PROTOBUF_C +-PROTOBUF_SOURCES += protobuf/google/protobuf-c/protobuf-c.h protobuf/google/protobuf-c/protobuf-c.c ++PROTOBUF_SOURCES += protobuf/protobuf-c/protobuf-c.h protobuf/protobuf-c/protobuf-c.c + endif + + # Files common to ocserv and occtl. +diff --git a/src/protobuf/google/protobuf-c/protobuf-c.c b/src/protobuf/google/protobuf-c/protobuf-c.c +deleted file mode 100644 +index c7fb21d..0000000 +--- a/src/protobuf/google/protobuf-c/protobuf-c.c ++++ /dev/null +@@ -1,3272 +0,0 @@ +-/* +- * 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 +- * met: +- * +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * +- * * Redistributions in binary form must reproduce the above +- * copyright notice, this list of conditions and the following disclaimer +- * in the documentation and/or other materials provided with the +- * distribution. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-/*! \file +- * Support library for `protoc-c` generated code. +- * +- * This file implements the public API used by the code generated +- * by `protoc-c`. +- * +- * \authors Dave Benson and the protobuf-c authors +- * +- * \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). +- * +- * \todo Use size_t consistently. +- */ +- +-#include /* for malloc, free */ +-#include /* for strcmp, strlen, memcpy, memmove, memset */ +- +-#include "protobuf-c.h" +- +-#define TRUE 1 +-#define FALSE 0 +- +-#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) +- +-/** +- * \defgroup internal Internal functions and macros +- * +- * These are not exported by the library but are useful to developers working +- * on `libprotobuf-c` itself. +- */ +- +-/** +- * \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) +- +-#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ +- 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) +- +-/**@}*/ +- +-/* --- version --- */ +- +-const char * +-protobuf_c_version(void) +-{ +- return PROTOBUF_C_VERSION; +-} +- +-uint32_t +-protobuf_c_version_number(void) +-{ +- return PROTOBUF_C_VERSION_NUMBER; +-} +- +-/* --- allocator --- */ +- +-static void * +-system_alloc(void *allocator_data, size_t size) +-{ +- return malloc(size); +-} +- +-static void +-system_free(void *allocator_data, void *data) +-{ +- free(data); +-} +- +-static inline void * +-do_alloc(ProtobufCAllocator *allocator, size_t size) +-{ +- return allocator->alloc(allocator->allocator_data, size); +-} +- +-static inline void +-do_free(ProtobufCAllocator *allocator, void *data) +-{ +- if (data != NULL) +- allocator->free(allocator->allocator_data, data); +-} +- +-/* +- * 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. +- */ +-static ProtobufCAllocator protobuf_c__allocator = { +- .alloc = &system_alloc, +- .free = &system_free, +- .allocator_data = NULL, +-}; +- +-/* === buffer-simple === */ +- +-void +-protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, +- size_t len, const uint8_t *data) +-{ +- ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) 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(allocator, new_alloced); +- if (!new_data) +- return; +- memcpy(new_data, simp->data, simp->len); +- if (simp->must_free_data) +- do_free(allocator, simp->data); +- else +- simp->must_free_data = TRUE; +- simp->data = new_data; +- simp->alloced = new_alloced; +- } +- memcpy(simp->data + simp->len, data, len); +- simp->len = new_len; +-} +- +-/** +- * \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) +-{ +- if (number < (1 << 4)) { +- return 1; +- } else if (number < (1 << 11)) { +- return 2; +- } else if (number < (1 << 18)) { +- return 3; +- } else if (number < (1 << 25)) { +- return 4; +- } else { +- return 5; +- } +-} +- +-/** +- * 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) +-{ +- if (v < (1 << 7)) { +- return 1; +- } else if (v < (1 << 14)) { +- return 2; +- } else if (v < (1 << 21)) { +- return 3; +- } else if (v < (1 << 28)) { +- return 4; +- } else { +- return 5; +- } +-} +- +-/** +- * 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) +-{ +- if (v < 0) { +- return 10; +- } else if (v < (1 << 7)) { +- return 1; +- } else if (v < (1 << 14)) { +- return 2; +- } else if (v < (1 << 21)) { +- return 3; +- } else if (v < (1 << 28)) { +- return 4; +- } else { +- return 5; +- } +-} +- +-/** +- * 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) +-{ +- if (v < 0) +- return ((uint32_t) (-v)) * 2 - 1; +- else +- 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) +-{ +- 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) +-{ +- uint32_t upper_v = (uint32_t) (v >> 32); +- +- if (upper_v == 0) { +- return uint32_size((uint32_t) v); +- } else if (upper_v < (1 << 3)) { +- return 5; +- } else if (upper_v < (1 << 10)) { +- return 6; +- } else if (upper_v < (1 << 17)) { +- return 7; +- } else if (upper_v < (1 << 24)) { +- return 8; +- } else if (upper_v < (1U << 31)) { +- return 9; +- } else { +- return 10; +- } +-} +- +-/** +- * 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) +-{ +- if (v < 0) +- return ((uint64_t) (-v)) * 2 - 1; +- else +- 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) +-{ +- 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, +- const void *member) +-{ +- size_t rv = get_tag_size(field->id); +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SINT32: +- return rv + sint32_size(*(const int32_t *) member); +- case PROTOBUF_C_TYPE_INT32: +- return rv + int32_size(*(const uint32_t *) member); +- case PROTOBUF_C_TYPE_UINT32: +- return rv + uint32_size(*(const uint32_t *) member); +- case PROTOBUF_C_TYPE_SINT64: +- return rv + sint64_size(*(const int64_t *) member); +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- return rv + uint64_size(*(const uint64_t *) member); +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- return rv + 4; +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- return rv + 8; +- case PROTOBUF_C_TYPE_BOOL: +- return rv + 1; +- case PROTOBUF_C_TYPE_FLOAT: +- return rv + 4; +- case PROTOBUF_C_TYPE_DOUBLE: +- return rv + 8; +- case PROTOBUF_C_TYPE_ENUM: +- /* \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; +- size_t len = str ? strlen(str) : 0; +- return rv + uint32_size(len) + len; +- } +- case PROTOBUF_C_TYPE_BYTES: { +- size_t len = ((const ProtobufCBinaryData *) member)->len; +- return rv + uint32_size(len) + len; +- } +- 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(); +- 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. +- * +- * \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, +- const void *member) +-{ +- if (field->type == PROTOBUF_C_TYPE_MESSAGE || +- field->type == PROTOBUF_C_TYPE_STRING) +- { +- const void *ptr = *(const void * const *) member; +- if (ptr == NULL || ptr == field->default_value) +- return 0; +- } else { +- if (!*has) +- return 0; +- } +- 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, +- size_t count, const void *member) +-{ +- size_t header_size; +- size_t rv = 0; +- unsigned i; +- void *array = *(void * const *) member; +- +- if (count == 0) +- return 0; +- header_size = get_tag_size(field->id); +- if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) +- header_size *= count; +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SINT32: +- for (i = 0; i < count; i++) +- rv += sint32_size(((int32_t *) array)[i]); +- break; +- case PROTOBUF_C_TYPE_INT32: +- for (i = 0; i < count; i++) +- rv += int32_size(((uint32_t *) array)[i]); +- break; +- case PROTOBUF_C_TYPE_UINT32: +- case PROTOBUF_C_TYPE_ENUM: +- for (i = 0; i < count; i++) +- rv += uint32_size(((uint32_t *) array)[i]); +- break; +- case PROTOBUF_C_TYPE_SINT64: +- for (i = 0; i < count; i++) +- rv += sint64_size(((int64_t *) array)[i]); +- break; +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- for (i = 0; i < count; i++) +- rv += uint64_size(((uint64_t *) array)[i]); +- break; +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- rv += 4 * count; +- break; +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- rv += 8 * count; +- break; +- case PROTOBUF_C_TYPE_BOOL: +- rv += count; +- break; +- case PROTOBUF_C_TYPE_STRING: +- for (i = 0; i < count; i++) { +- size_t len = strlen(((char **) array)[i]); +- rv += uint32_size(len) + len; +- } +- break; +- case PROTOBUF_C_TYPE_BYTES: +- for (i = 0; i < count; i++) { +- size_t len = ((ProtobufCBinaryData *) array)[i].len; +- rv += uint32_size(len) + len; +- } +- break; +- case PROTOBUF_C_TYPE_MESSAGE: +- for (i = 0; i < count; i++) { +- size_t len = protobuf_c_message_get_packed_size( +- ((ProtobufCMessage **) array)[i]); +- rv += uint32_size(len) + len; +- } +- break; +- } +- +- 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) +-{ +- return get_tag_size(field->tag) + field->len; +-} +- +-/**@}*/ +- +-/* +- * Calculate the serialized size of the message. +- */ +-size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) +-{ +- unsigned i; +- size_t rv = 0; +- +- ASSERT_IS_MESSAGE(message); +- for (i = 0; i < message->descriptor->n_fields; i++) { +- const ProtobufCFieldDescriptor *field = +- message->descriptor->fields + i; +- const void *member = +- ((const char *) message) + field->offset; +- const void *qmember = +- ((const char *) message) + field->quantifier_offset; +- +- if (field->label == PROTOBUF_C_LABEL_REQUIRED) { +- rv += required_field_get_packed_size(field, member); +- } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { +- rv += optional_field_get_packed_size(field, qmember, member); +- } else { +- rv += repeated_field_get_packed_size( +- field, +- *(const size_t *) qmember, +- member +- ); +- } +- } +- for (i = 0; i < message->n_unknown_fields; i++) +- rv += unknown_field_get_packed_size(&message->unknown_fields[i]); +- return rv; +-} +- +-/** +- * \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) +-{ +- unsigned rv = 0; +- +- if (value >= 0x80) { +- out[rv++] = value | 0x80; +- value >>= 7; +- if (value >= 0x80) { +- out[rv++] = value | 0x80; +- value >>= 7; +- if (value >= 0x80) { +- out[rv++] = value | 0x80; +- value >>= 7; +- if (value >= 0x80) { +- out[rv++] = value | 0x80; +- value >>= 7; +- } +- } +- } +- } +- /* assert: value<128 */ +- out[rv++] = value; +- 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) +-{ +- if (value < 0) { +- out[0] = value | 0x80; +- out[1] = (value >> 7) | 0x80; +- out[2] = (value >> 14) | 0x80; +- out[3] = (value >> 21) | 0x80; +- out[4] = (value >> 28) | 0x80; +- out[5] = out[6] = out[7] = out[8] = 0xff; +- out[9] = 0x01; +- return 10; +- } else { +- return uint32_pack(value, 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) +-{ +- 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) +-{ +- uint32_t hi = (uint32_t) (value >> 32); +- uint32_t lo = (uint32_t) value; +- unsigned rv; +- +- if (hi == 0) +- return uint32_pack((uint32_t) lo, out); +- out[0] = (lo) | 0x80; +- out[1] = (lo >> 7) | 0x80; +- out[2] = (lo >> 14) | 0x80; +- out[3] = (lo >> 21) | 0x80; +- if (hi < 8) { +- out[4] = (hi << 4) | (lo >> 28); +- return 5; +- } else { +- out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; +- hi >>= 3; +- } +- rv = 5; +- while (hi >= 128) { +- out[rv++] = hi | 0x80; +- hi >>= 7; +- } +- out[rv++] = hi; +- 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) +-{ +- 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) +-{ +-#if !defined(WORDS_BIGENDIAN) +- memcpy(out, &value, 4); +-#else +- uint8_t *buf = out; +- +- buf[0] = value; +- buf[1] = value >> 8; +- buf[2] = value >> 16; +- buf[3] = value >> 24; +-#endif +- return 4; +-} +- +-/** +- * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire +- * types fixed64, sfixed64, double. Similar to "htole64". +- * +- * \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) +-{ +-#if !defined(WORDS_BIGENDIAN) +- memcpy(out, &value, 8); +-#else +- fixed32_pack(value, out); +- fixed32_pack(value >> 32, ((char *) out) + 4); +-#endif +- return 8; +-} +- +-/** +- * Pack a boolean value as an integer and return the number of bytes written. +- * +- * \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 ? 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 +- * 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) +-{ +- if (str == NULL) { +- out[0] = 0; +- return 1; +- } else { +- size_t len = strlen(str); +- size_t rv = uint32_pack(len, out); +- memcpy(out + rv, str, len); +- return rv + len; +- } +-} +- +-/** +- * 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) +-{ +- size_t len = bd->len; +- size_t rv = uint32_pack(len, out); +- memcpy(out + rv, bd->data, len); +- 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) +-{ +- if (message == NULL) { +- out[0] = 0; +- return 1; +- } else { +- size_t rv = protobuf_c_message_pack(message, out + 1); +- uint32_t rv_packed_size = uint32_size(rv); +- if (rv_packed_size != 1) +- memmove(out + rv_packed_size, out + 1, rv); +- return uint32_pack(rv, out) + rv; +- } +-} +- +-/** +- * 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) +-{ +- if (id < (1 << (32 - 3))) +- return uint32_pack(id << 3, out); +- else +- 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) +-{ +- size_t rv = tag_pack(field->id, out); +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SINT32: +- out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- return rv + sint32_pack(*(const int32_t *) member, out + rv); +- case PROTOBUF_C_TYPE_INT32: +- out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- return rv + int32_pack(*(const uint32_t *) member, out + rv); +- case PROTOBUF_C_TYPE_UINT32: +- case PROTOBUF_C_TYPE_ENUM: +- out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- return rv + uint32_pack(*(const uint32_t *) member, out + rv); +- case PROTOBUF_C_TYPE_SINT64: +- out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- return rv + sint64_pack(*(const int64_t *) member, out + rv); +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- return rv + uint64_pack(*(const uint64_t *) member, out + rv); +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; +- return rv + fixed32_pack(*(const uint32_t *) member, out + rv); +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; +- return rv + fixed64_pack(*(const uint64_t *) member, out + rv); +- case PROTOBUF_C_TYPE_BOOL: +- out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); +- case PROTOBUF_C_TYPE_STRING: +- out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- return rv + string_pack(*(char *const *) member, out + rv); +- 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_MESSAGE: +- out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); +- } +- 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, +- const void *member, uint8_t *out) +-{ +- if (field->type == PROTOBUF_C_TYPE_MESSAGE || +- field->type == PROTOBUF_C_TYPE_STRING) +- { +- const void *ptr = *(const void * const *) member; +- if (ptr == NULL || ptr == field->default_value) +- return 0; +- } else { +- if (!*has) +- return 0; +- } +- return required_field_pack(field, member, out); +-} +- +-/** +- * 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) +-{ +- switch (type) { +- case PROTOBUF_C_TYPE_SINT32: +- case PROTOBUF_C_TYPE_INT32: +- case PROTOBUF_C_TYPE_UINT32: +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- case PROTOBUF_C_TYPE_ENUM: +- return 4; +- case PROTOBUF_C_TYPE_SINT64: +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- return 8; +- case PROTOBUF_C_TYPE_BOOL: +- return sizeof(protobuf_c_boolean); +- case PROTOBUF_C_TYPE_STRING: +- case PROTOBUF_C_TYPE_MESSAGE: +- return sizeof(void *); +- case PROTOBUF_C_TYPE_BYTES: +- return sizeof(ProtobufCBinaryData); +- } +- 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) +-{ +-#if !defined(WORDS_BIGENDIAN) +- memcpy(out, in, n * 4); +-#else +- unsigned i; +- const uint32_t *ini = in; +- for (i = 0; i < n; i++) +- fixed32_pack(ini[i], (uint32_t *) out + i); +-#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) +-{ +-#if !defined(WORDS_BIGENDIAN) +- memcpy(out, in, n * 8); +-#else +- unsigned i; +- const uint64_t *ini = in; +- for (i = 0; i < n; i++) +- fixed64_pack(ini[i], (uint64_t *) out + i); +-#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) +-{ +- if (type == PROTOBUF_C_TYPE_SFIXED32 || +- type == PROTOBUF_C_TYPE_FIXED32 || +- type == PROTOBUF_C_TYPE_FLOAT) +- { +- return 4; +- } +- if (type == PROTOBUF_C_TYPE_SFIXED64 || +- type == PROTOBUF_C_TYPE_FIXED64 || +- type == PROTOBUF_C_TYPE_DOUBLE) +- { +- return 8; +- } +- 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) +-{ +- void *array = *(void * const *) member; +- unsigned i; +- +- if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { +- unsigned header_len; +- unsigned len_start; +- unsigned min_length; +- unsigned payload_len; +- unsigned length_size_min; +- unsigned actual_length_size; +- uint8_t *payload_at; +- +- if (count == 0) +- return 0; +- header_len = tag_pack(field->id, out); +- out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- len_start = header_len; +- min_length = get_type_min_size(field->type) * count; +- length_size_min = uint32_size(min_length); +- header_len += length_size_min; +- payload_at = out + header_len; +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- copy_to_little_endian_32(payload_at, array, count); +- payload_at += count * 4; +- break; +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- copy_to_little_endian_64(payload_at, array, count); +- payload_at += count * 8; +- break; +- case PROTOBUF_C_TYPE_INT32: { +- const int32_t *arr = (const int32_t *) array; +- for (i = 0; i < count; i++) +- payload_at += int32_pack(arr[i], payload_at); +- break; +- } +- case PROTOBUF_C_TYPE_SINT32: { +- const int32_t *arr = (const int32_t *) array; +- for (i = 0; i < count; i++) +- payload_at += sint32_pack(arr[i], payload_at); +- break; +- } +- case PROTOBUF_C_TYPE_SINT64: { +- const int64_t *arr = (const int64_t *) array; +- for (i = 0; i < count; i++) +- payload_at += sint64_pack(arr[i], payload_at); +- break; +- } +- case PROTOBUF_C_TYPE_ENUM: +- case PROTOBUF_C_TYPE_UINT32: { +- const uint32_t *arr = (const uint32_t *) array; +- for (i = 0; i < count; i++) +- payload_at += uint32_pack(arr[i], payload_at); +- break; +- } +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: { +- const uint64_t *arr = (const uint64_t *) array; +- for (i = 0; i < count; i++) +- payload_at += uint64_pack(arr[i], payload_at); +- break; +- } +- case PROTOBUF_C_TYPE_BOOL: { +- const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; +- for (i = 0; i < count; i++) +- payload_at += boolean_pack(arr[i], payload_at); +- break; +- } +- default: +- PROTOBUF_C__ASSERT_NOT_REACHED(); +- } +- +- payload_len = payload_at - (out + header_len); +- actual_length_size = uint32_size(payload_len); +- if (length_size_min != actual_length_size) { +- assert(actual_length_size == length_size_min + 1); +- memmove(out + header_len + 1, out + header_len, +- payload_len); +- header_len++; +- } +- uint32_pack(payload_len, out + len_start); +- return header_len + payload_len; +- } else { +- /* 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 = (char *)array + siz; +- } +- return rv; +- } +-} +- +-static size_t +-unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) +-{ +- size_t rv = tag_pack(field->tag, out); +- out[0] |= field->wire_type; +- memcpy(out + rv, field->data, field->len); +- return rv + field->len; +-} +- +-/**@}*/ +- +-size_t +-protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) +-{ +- unsigned i; +- size_t rv = 0; +- +- ASSERT_IS_MESSAGE(message); +- for (i = 0; i < message->descriptor->n_fields; i++) { +- const ProtobufCFieldDescriptor *field = +- message->descriptor->fields + i; +- const void *member = ((const char *) message) + field->offset; +- +- /* +- * It doesn't hurt to compute qmember (a pointer to the +- * quantifier field of the structure), but the pointer is only +- * valid if the field is: +- * - a repeated field, or +- * - an optional field that isn't a pointer type +- * (Meaning: not a message or a string). +- */ +- const void *qmember = +- ((const char *) message) + field->quantifier_offset; +- +- if (field->label == PROTOBUF_C_LABEL_REQUIRED) { +- rv += required_field_pack(field, member, out + rv); +- } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { +- /* +- * Note that qmember is bogus for strings and messages, +- * but it isn't used. +- */ +- rv += optional_field_pack(field, qmember, member, out + rv); +- } else { +- rv += repeated_field_pack(field, *(const size_t *) qmember, +- member, out + rv); +- } +- } +- for (i = 0; i < message->n_unknown_fields; i++) +- rv += unknown_field_pack(&message->unknown_fields[i], out + rv); +- return rv; +-} +- +-/** +- * \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) +-{ +- size_t rv; +- uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; +- +- rv = tag_pack(field->id, scratch); +- switch (field->type) { +- case PROTOBUF_C_TYPE_SINT32: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- rv += sint32_pack(*(const int32_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_INT32: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- rv += int32_pack(*(const uint32_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_UINT32: +- case PROTOBUF_C_TYPE_ENUM: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- rv += uint32_pack(*(const uint32_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_SINT64: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- rv += sint64_pack(*(const int64_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- rv += uint64_pack(*(const uint64_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; +- rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; +- rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_BOOL: +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; +- rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); +- buffer->append(buffer, rv, scratch); +- break; +- case PROTOBUF_C_TYPE_STRING: { +- const char *str = *(char *const *) member; +- size_t sublen = str ? strlen(str) : 0; +- +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- rv += uint32_pack(sublen, scratch + rv); +- buffer->append(buffer, rv, scratch); +- buffer->append(buffer, sublen, (const uint8_t *) str); +- rv += sublen; +- break; +- } +- case PROTOBUF_C_TYPE_BYTES: { +- const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); +- size_t sublen = bd->len; +- +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- rv += uint32_pack(sublen, scratch + rv); +- buffer->append(buffer, rv, scratch); +- buffer->append(buffer, sublen, bd->data); +- rv += sublen; +- break; +- } +- case PROTOBUF_C_TYPE_MESSAGE: { +- uint8_t simple_buffer_scratch[256]; +- size_t sublen; +- const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; +- ProtobufCBufferSimple simple_buffer = +- PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch); +- +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- if (msg == NULL) +- sublen = 0; +- else +- sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); +- rv += uint32_pack(sublen, scratch + rv); +- buffer->append(buffer, rv, scratch); +- buffer->append(buffer, sublen, simple_buffer.data); +- rv += sublen; +- PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); +- break; +- } +- default: +- 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, +- const void *member, ProtobufCBuffer *buffer) +-{ +- if (field->type == PROTOBUF_C_TYPE_MESSAGE || +- field->type == PROTOBUF_C_TYPE_STRING) +- { +- const void *ptr = *(const void *const *) member; +- if (ptr == NULL || ptr == field->default_value) +- return 0; +- } else { +- if (!*has) +- return 0; +- } +- 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) +-{ +- unsigned rv = 0; +- unsigned i; +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- return count * 4; +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- return count * 8; +- case PROTOBUF_C_TYPE_INT32: { +- const int32_t *arr = (const int32_t *) array; +- for (i = 0; i < count; i++) +- rv += int32_size(arr[i]); +- break; +- } +- case PROTOBUF_C_TYPE_SINT32: { +- const int32_t *arr = (const int32_t *) array; +- for (i = 0; i < count; i++) +- rv += sint32_size(arr[i]); +- break; +- } +- case PROTOBUF_C_TYPE_ENUM: +- case PROTOBUF_C_TYPE_UINT32: { +- const uint32_t *arr = (const uint32_t *) array; +- for (i = 0; i < count; i++) +- rv += uint32_size(arr[i]); +- break; +- } +- case PROTOBUF_C_TYPE_SINT64: { +- const int64_t *arr = (const int64_t *) array; +- for (i = 0; i < count; i++) +- rv += sint64_size(arr[i]); +- break; +- } +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: { +- const uint64_t *arr = (const uint64_t *) array; +- for (i = 0; i < count; i++) +- rv += uint64_size(arr[i]); +- break; +- } +- case PROTOBUF_C_TYPE_BOOL: +- return count; +- default: +- 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, +- ProtobufCBuffer *buffer) +-{ +- uint8_t scratch[16]; +- size_t rv = 0; +- unsigned i; +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +-#if !defined(WORDS_BIGENDIAN) +- rv = count * 4; +- goto no_packing_needed; +-#else +- for (i = 0; i < count; i++) { +- unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +-#endif +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +-#if !defined(WORDS_BIGENDIAN) +- rv = count * 8; +- goto no_packing_needed; +-#else +- for (i = 0; i < count; i++) { +- unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +-#endif +- case PROTOBUF_C_TYPE_INT32: +- for (i = 0; i < count; i++) { +- unsigned len = int32_pack(((int32_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +- case PROTOBUF_C_TYPE_SINT32: +- for (i = 0; i < count; i++) { +- unsigned len = sint32_pack(((int32_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +- case PROTOBUF_C_TYPE_ENUM: +- case PROTOBUF_C_TYPE_UINT32: +- for (i = 0; i < count; i++) { +- unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +- case PROTOBUF_C_TYPE_SINT64: +- for (i = 0; i < count; i++) { +- unsigned len = sint64_pack(((int64_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- for (i = 0; i < count; i++) { +- unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- break; +- case PROTOBUF_C_TYPE_BOOL: +- for (i = 0; i < count; i++) { +- unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); +- buffer->append(buffer, len, scratch); +- rv += len; +- } +- return count; +- default: +- PROTOBUF_C__ASSERT_NOT_REACHED(); +- } +- return rv; +- +-no_packing_needed: +- buffer->append(buffer, rv, array); +- return rv; +-} +- +-static size_t +-repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, +- unsigned count, const void *member, +- ProtobufCBuffer *buffer) +-{ +- char *array = *(char * const *) member; +- +- if (count == 0) +- return 0; +- 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); +- size_t tmp; +- +- scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; +- rv += uint32_pack(payload_len, scratch + rv); +- buffer->append(buffer, rv, scratch); +- tmp = pack_buffer_packed_payload(field, count, array, buffer); +- assert(tmp == payload_len); +- return rv + payload_len; +- } else { +- size_t siz; +- unsigned i; +- /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ +- unsigned rv = 0; +- +- siz = sizeof_elt_in_repeated_array(field->type); +- for (i = 0; i < count; i++) { +- rv += required_field_pack_to_buffer(field, array, buffer); +- array += siz; +- } +- return rv; +- } +-} +- +-static size_t +-unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, +- ProtobufCBuffer *buffer) +-{ +- uint8_t header[MAX_UINT64_ENCODED_SIZE]; +- size_t rv = tag_pack(field->tag, header); +- +- header[0] |= field->wire_type; +- buffer->append(buffer, rv, header); +- buffer->append(buffer, field->len, field->data); +- return rv + field->len; +-} +- +-/**@}*/ +- +-size_t +-protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, +- ProtobufCBuffer *buffer) +-{ +- unsigned i; +- size_t rv = 0; +- +- ASSERT_IS_MESSAGE(message); +- for (i = 0; i < message->descriptor->n_fields; i++) { +- const ProtobufCFieldDescriptor *field = +- message->descriptor->fields + i; +- const void *member = +- ((const char *) message) + field->offset; +- const void *qmember = +- ((const char *) message) + field->quantifier_offset; +- +- if (field->label == PROTOBUF_C_LABEL_REQUIRED) { +- rv += required_field_pack_to_buffer(field, member, buffer); +- } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { +- rv += optional_field_pack_to_buffer( +- field, +- qmember, +- member, +- buffer +- ); +- } else { +- rv += repeated_field_pack_to_buffer( +- field, +- *(const size_t *) qmember, +- member, +- buffer +- ); +- } +- } +- for (i = 0; i < message->n_unknown_fields; i++) +- rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer); +- +- return rv; +-} +- +-/** +- * \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) +-{ +- unsigned n; +- unsigned start; +- +- if (n_ranges == 0) +- return -1; +- start = 0; +- n = n_ranges; +- while (n > 1) { +- unsigned mid = start + n / 2; +- +- if (value < ranges[mid].start_value) { +- n = mid - start; +- } else if (value >= ranges[mid].start_value + +- (int) (ranges[mid + 1].orig_index - +- ranges[mid].orig_index)) +- { +- unsigned new_start = mid + 1; +- n = start + n - new_start; +- start = new_start; +- } else +- return (value - ranges[mid].start_value) + +- ranges[mid].orig_index; +- } +- if (n > 0) { +- unsigned start_orig_index = ranges[start].orig_index; +- unsigned range_size = +- ranges[start + 1].orig_index - start_orig_index; +- +- if (ranges[start].start_value <= value && +- value < (int) (ranges[start].start_value + range_size)) +- { +- return (value - ranges[start].start_value) + +- start_orig_index; +- } +- } +- return -1; +-} +- +-static size_t +-parse_tag_and_wiretype(size_t len, +- const uint8_t *data, +- uint32_t *tag_out, +- ProtobufCWireType *wiretype_out) +-{ +- unsigned max_rv = len > 5 ? 5 : len; +- uint32_t tag = (data[0] & 0x7f) >> 3; +- unsigned shift = 4; +- unsigned rv; +- +- *wiretype_out = data[0] & 7; +- if ((data[0] & 0x80) == 0) { +- *tag_out = tag; +- return 1; +- } +- for (rv = 1; rv < max_rv; rv++) { +- if (data[rv] & 0x80) { +- tag |= (data[rv] & 0x7f) << shift; +- shift += 7; +- } else { +- tag |= data[rv] << shift; +- *tag_out = tag; +- return rv + 1; +- } +- } +- return 0; /* error: bad header */ +-} +- +-/* sizeof(ScannedMember) must be <= (1< len) { +- PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); +- return 0; +- } +- return hdr_len + val; +-} +- +-static size_t +-max_b128_numbers(size_t len, const uint8_t *data) +-{ +- size_t rv = 0; +- while (len--) +- if ((*data++ & 0x80) == 0) +- ++rv; +- return rv; +-} +- +-/**@}*/ +- +-/** +- * Merge earlier message into a latter message. +- * +- * For numeric types and strings, if the same value appears multiple +- * times, the parser accepts the last value it sees. For embedded +- * message fields, the parser merges multiple instances of the same +- * field. That is, all singular scalar fields in the latter instance +- * replace those in the former, singular embedded messages are merged, +- * and repeated fields are concatenated. +- * +- * The earlier message should be freed after calling this function, as +- * some of its fields may have been reused and changed to their default +- * values during the merge. +- */ +-static protobuf_c_boolean +-merge_messages(ProtobufCMessage *earlier_msg, +- ProtobufCMessage *latter_msg, +- ProtobufCAllocator *allocator) +-{ +- unsigned i; +- const ProtobufCFieldDescriptor *fields = +- earlier_msg->descriptor->fields; +- for (i = 0; i < latter_msg->descriptor->n_fields; i++) { +- if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { +- size_t *n_earlier = +- STRUCT_MEMBER_PTR(size_t, earlier_msg, +- fields[i].quantifier_offset); +- uint8_t **p_earlier = +- STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, +- fields[i].offset); +- size_t *n_latter = +- STRUCT_MEMBER_PTR(size_t, latter_msg, +- fields[i].quantifier_offset); +- uint8_t **p_latter = +- STRUCT_MEMBER_PTR(uint8_t *, latter_msg, +- fields[i].offset); +- +- if (*n_earlier > 0) { +- if (*n_latter > 0) { +- /* Concatenate the repeated field */ +- size_t el_size = +- sizeof_elt_in_repeated_array(fields[i].type); +- uint8_t *new_field; +- +- new_field = do_alloc(allocator, +- (*n_earlier + *n_latter) * el_size); +- if (!new_field) +- return FALSE; +- +- memcpy(new_field, *p_earlier, +- *n_earlier * el_size); +- memcpy(new_field + +- *n_earlier * el_size, +- *p_latter, +- *n_latter * el_size); +- +- do_free(allocator, *p_latter); +- do_free(allocator, *p_earlier); +- *p_latter = new_field; +- *n_latter = *n_earlier + *n_latter; +- } else { +- /* Zero copy the repeated field from the earlier message */ +- *n_latter = *n_earlier; +- *p_latter = *p_earlier; +- } +- /* Make sure the field does not get double freed */ +- *n_earlier = 0; +- *p_earlier = 0; +- } +- } else if (fields[i].type == PROTOBUF_C_TYPE_MESSAGE) { +- ProtobufCMessage **em = +- STRUCT_MEMBER_PTR(ProtobufCMessage *, +- earlier_msg, +- fields[i].offset); +- ProtobufCMessage **lm = +- STRUCT_MEMBER_PTR(ProtobufCMessage *, +- latter_msg, +- fields[i].offset); +- if (*em != NULL) { +- if (*lm != NULL) { +- if (!merge_messages +- (*em, *lm, allocator)) +- return FALSE; +- } else { +- /* Zero copy the optional message */ +- assert(fields[i].label == +- PROTOBUF_C_LABEL_OPTIONAL); +- *lm = *em; +- *em = NULL; +- } +- } +- } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL) { +- size_t el_size = 0; +- protobuf_c_boolean need_to_merge = FALSE; +- void *earlier_elem = +- STRUCT_MEMBER_P(earlier_msg, fields[i].offset); +- void *latter_elem = +- STRUCT_MEMBER_P(latter_msg, fields[i].offset); +- const void *def_val = fields[i].default_value; +- +- switch (fields[i].type) { +- case PROTOBUF_C_TYPE_BYTES: { +- el_size = sizeof(ProtobufCBinaryData); +- uint8_t *e_data = +- ((ProtobufCBinaryData *) earlier_elem)->data; +- uint8_t *l_data = +- ((ProtobufCBinaryData *) latter_elem)->data; +- const ProtobufCBinaryData *d_bd = +- (ProtobufCBinaryData *) def_val; +- +- need_to_merge = +- (e_data != NULL && +- (d_bd != NULL && +- e_data != d_bd->data)) && +- (l_data == NULL || +- (d_bd != NULL && +- l_data == d_bd->data)); +- break; +- } +- case PROTOBUF_C_TYPE_STRING: { +- el_size = sizeof(char *); +- char *e_str = *(char **) earlier_elem; +- char *l_str = *(char **) latter_elem; +- const char *d_str = def_val; +- +- need_to_merge = e_str != d_str && l_str == d_str; +- break; +- } +- default: { +- el_size = sizeof_elt_in_repeated_array(fields[i].type); +- +- need_to_merge = +- STRUCT_MEMBER(protobuf_c_boolean, +- earlier_msg, +- fields[i].quantifier_offset) && +- !STRUCT_MEMBER(protobuf_c_boolean, +- latter_msg, +- fields[i].quantifier_offset); +- break; +- } +- } +- +- if (need_to_merge) { +- memcpy(latter_elem, earlier_elem, el_size); +- /* +- * Reset the element from the old message to 0 +- * to make sure earlier message deallocation +- * doesn't corrupt zero-copied data in the new +- * message, earlier message will be freed after +- * this function is called anyway +- */ +- memset(earlier_elem, 0, el_size); +- +- if (fields[i].quantifier_offset != 0) { +- /* Set the has field, if applicable */ +- STRUCT_MEMBER(protobuf_c_boolean, +- latter_msg, +- fields[i]. +- quantifier_offset) = TRUE; +- STRUCT_MEMBER(protobuf_c_boolean, +- earlier_msg, +- fields[i]. +- quantifier_offset) = FALSE; +- } +- } +- } +- } +- return TRUE; +-} +- +-/** +- * 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) +-{ +- switch (type) { +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- if (len % 4 != 0) { +- PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); +- return FALSE; +- } +- *count_out = len / 4; +- return TRUE; +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- if (len % 8 != 0) { +- PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); +- return FALSE; +- } +- *count_out = len / 8; +- return TRUE; +- case PROTOBUF_C_TYPE_INT32: +- case PROTOBUF_C_TYPE_SINT32: +- case PROTOBUF_C_TYPE_ENUM: +- case PROTOBUF_C_TYPE_UINT32: +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_SINT64: +- case PROTOBUF_C_TYPE_UINT64: +- *count_out = max_b128_numbers(len, data); +- return TRUE; +- case PROTOBUF_C_TYPE_BOOL: +- *count_out = len; +- return TRUE; +- case PROTOBUF_C_TYPE_STRING: +- case PROTOBUF_C_TYPE_BYTES: +- case PROTOBUF_C_TYPE_MESSAGE: +- default: +- PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); +- return FALSE; +- } +-} +- +-static inline uint32_t +-parse_uint32(unsigned len, const uint8_t *data) +-{ +- uint32_t rv = data[0] & 0x7f; +- if (len > 1) { +- rv |= ((uint32_t) (data[1] & 0x7f) << 7); +- if (len > 2) { +- rv |= ((uint32_t) (data[2] & 0x7f) << 14); +- if (len > 3) { +- rv |= ((uint32_t) (data[3] & 0x7f) << 21); +- if (len > 4) +- rv |= ((uint32_t) (data[4]) << 28); +- } +- } +- } +- return rv; +-} +- +-static inline uint32_t +-parse_int32(unsigned len, const uint8_t *data) +-{ +- return parse_uint32(len, data); +-} +- +-static inline int32_t +-unzigzag32(uint32_t v) +-{ +- if (v & 1) +- return -(v >> 1) - 1; +- else +- return v >> 1; +-} +- +-static inline uint32_t +-parse_fixed_uint32(const uint8_t *data) +-{ +-#if !defined(WORDS_BIGENDIAN) +- uint32_t t; +- memcpy(&t, data, 4); +- return t; +-#else +- return data[0] | +- ((uint32_t) (data[1]) << 8) | +- ((uint32_t) (data[2]) << 16) | +- ((uint32_t) (data[3]) << 24); +-#endif +-} +- +-static uint64_t +-parse_uint64(unsigned len, const uint8_t *data) +-{ +- unsigned shift, i; +- uint64_t rv; +- +- if (len < 5) +- return parse_uint32(len, data); +- rv = ((uint64_t) (data[0] & 0x7f)) | +- ((uint64_t) (data[1] & 0x7f) << 7) | +- ((uint64_t) (data[2] & 0x7f) << 14) | +- ((uint64_t) (data[3] & 0x7f) << 21); +- shift = 28; +- for (i = 4; i < len; i++) { +- rv |= (((uint64_t) (data[i] & 0x7f)) << shift); +- shift += 7; +- } +- return rv; +-} +- +-static inline int64_t +-unzigzag64(uint64_t v) +-{ +- if (v & 1) +- return -(v >> 1) - 1; +- else +- return v >> 1; +-} +- +-static inline uint64_t +-parse_fixed_uint64(const uint8_t *data) +-{ +-#if !defined(WORDS_BIGENDIAN) +- uint64_t t; +- memcpy(&t, data, 8); +- return t; +-#else +- return (uint64_t) parse_fixed_uint32(data) | +- (((uint64_t) parse_fixed_uint32(data + 4)) << 32); +-#endif +-} +- +-static protobuf_c_boolean +-parse_boolean(unsigned len, const uint8_t *data) +-{ +- unsigned i; +- for (i = 0; i < len; i++) +- if (data[i] & 0x7f) +- return TRUE; +- return FALSE; +-} +- +-static protobuf_c_boolean +-parse_required_member(ScannedMember *scanned_member, +- void *member, +- ProtobufCAllocator *allocator, +- protobuf_c_boolean maybe_clear) +-{ +- unsigned len = scanned_member->len; +- const uint8_t *data = scanned_member->data; +- ProtobufCWireType wire_type = scanned_member->wire_type; +- +- switch (scanned_member->field->type) { +- case PROTOBUF_C_TYPE_INT32: +- if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) +- return FALSE; +- *(uint32_t *) member = parse_int32(len, data); +- return TRUE; +- case PROTOBUF_C_TYPE_UINT32: +- if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) +- return FALSE; +- *(uint32_t *) member = parse_uint32(len, data); +- return TRUE; +- case PROTOBUF_C_TYPE_SINT32: +- if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) +- return FALSE; +- *(int32_t *) member = unzigzag32(parse_uint32(len, data)); +- 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 FALSE; +- *(uint32_t *) member = parse_fixed_uint32(data); +- return TRUE; +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) +- return FALSE; +- *(uint64_t *) member = parse_uint64(len, data); +- return TRUE; +- case PROTOBUF_C_TYPE_SINT64: +- if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) +- return FALSE; +- *(int64_t *) member = unzigzag64(parse_uint64(len, data)); +- 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 FALSE; +- *(uint64_t *) member = parse_fixed_uint64(data); +- return TRUE; +- case PROTOBUF_C_TYPE_BOOL: +- *(protobuf_c_boolean *) member = parse_boolean(len, data); +- return TRUE; +- case PROTOBUF_C_TYPE_ENUM: +- if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) +- return FALSE; +- *(uint32_t *) member = parse_uint32(len, data); +- 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 FALSE; +- +- if (maybe_clear && *pstr != NULL) { +- const char *def = scanned_member->field->default_value; +- if (*pstr != NULL && *pstr != def) +- do_free(allocator, *pstr); +- } +- *pstr = do_alloc(allocator, len - pref_len + 1); +- if (*pstr == NULL) +- return FALSE; +- memcpy(*pstr, data + pref_len, len - pref_len); +- (*pstr)[len - pref_len] = 0; +- return TRUE; +- } +- case PROTOBUF_C_TYPE_BYTES: { +- ProtobufCBinaryData *bd = member; +- const ProtobufCBinaryData *def_bd; +- unsigned pref_len = scanned_member->length_prefix_len; +- +- if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) +- return FALSE; +- +- def_bd = scanned_member->field->default_value; +- if (maybe_clear && +- bd->data != NULL && +- (def_bd == NULL || bd->data != def_bd->data)) +- { +- do_free(allocator, bd->data); +- } +- if (len - pref_len > 0) { +- bd->data = do_alloc(allocator, len - pref_len); +- if (bd->data == NULL) +- return FALSE; +- memcpy(bd->data, data + pref_len, len - pref_len); +- } +- bd->len = len - pref_len; +- return TRUE; +- } +- case PROTOBUF_C_TYPE_MESSAGE: { +- ProtobufCMessage **pmessage = member; +- ProtobufCMessage *subm; +- const ProtobufCMessage *def_mess; +- protobuf_c_boolean merge_successful = TRUE; +- unsigned pref_len = scanned_member->length_prefix_len; +- +- if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) +- return FALSE; +- +- def_mess = scanned_member->field->default_value; +- subm = protobuf_c_message_unpack(scanned_member->field->descriptor, +- allocator, +- len - pref_len, +- data + pref_len); +- +- if (maybe_clear && +- *pmessage != NULL && +- *pmessage != def_mess) +- { +- if (subm != NULL) +- merge_successful = merge_messages(*pmessage, subm, allocator); +- /* Delete the previous message */ +- protobuf_c_message_free_unpacked(*pmessage, allocator); +- } +- *pmessage = subm; +- if (subm == NULL || !merge_successful) +- return FALSE; +- return TRUE; +- } +- } +- return FALSE; +-} +- +-static protobuf_c_boolean +-parse_optional_member(ScannedMember *scanned_member, +- void *member, +- ProtobufCMessage *message, +- ProtobufCAllocator *allocator) +-{ +- if (!parse_required_member(scanned_member, member, allocator, TRUE)) +- return FALSE; +- if (scanned_member->field->quantifier_offset != 0) +- STRUCT_MEMBER(protobuf_c_boolean, +- message, +- scanned_member->field->quantifier_offset) = TRUE; +- return TRUE; +-} +- +-static protobuf_c_boolean +-parse_repeated_member(ScannedMember *scanned_member, +- void *member, +- ProtobufCMessage *message, +- ProtobufCAllocator *allocator) +-{ +- 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; +- +- if (!parse_required_member(scanned_member, array + siz * (*p_n), +- allocator, FALSE)) +- { +- return FALSE; +- } +- *p_n += 1; +- return TRUE; +-} +- +-static unsigned +-scan_varint(unsigned len, const uint8_t *data) +-{ +- unsigned i; +- if (len > 10) +- len = 10; +- for (i = 0; i < len; i++) +- if ((data[i] & 0x80) == 0) +- break; +- if (i == len) +- return 0; +- return i + 1; +-} +- +-static protobuf_c_boolean +-parse_packed_repeated_member(ScannedMember *scanned_member, +- void *member, +- ProtobufCMessage *message) +-{ +- 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); +- 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; +- unsigned i; +- +- switch (field->type) { +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- count = (scanned_member->len - scanned_member->length_prefix_len) / 4; +-#if !defined(WORDS_BIGENDIAN) +- goto no_unpacking_needed; +-#else +- for (i = 0; i < count; i++) { +- ((uint32_t *) array)[i] = parse_fixed_uint32(at); +- at += 4; +- } +- break; +-#endif +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- count = (scanned_member->len - scanned_member->length_prefix_len) / 8; +-#if !defined(WORDS_BIGENDIAN) +- goto no_unpacking_needed; +-#else +- for (i = 0; i < count; i++) { +- ((uint64_t *) array)[i] = parse_fixed_uint64(at); +- at += 8; +- } +- break; +-#endif +- case PROTOBUF_C_TYPE_INT32: +- while (rem > 0) { +- unsigned s = scan_varint(rem, at); +- if (s == 0) { +- PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); +- return FALSE; +- } +- ((int32_t *) array)[count++] = parse_int32(s, at); +- at += s; +- rem -= s; +- } +- break; +- case PROTOBUF_C_TYPE_SINT32: +- while (rem > 0) { +- unsigned s = scan_varint(rem, at); +- if (s == 0) { +- PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); +- return FALSE; +- } +- ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); +- at += s; +- rem -= s; +- } +- break; +- case PROTOBUF_C_TYPE_ENUM: +- case PROTOBUF_C_TYPE_UINT32: +- while (rem > 0) { +- unsigned s = scan_varint(rem, at); +- if (s == 0) { +- PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); +- return FALSE; +- } +- ((uint32_t *) array)[count++] = parse_uint32(s, at); +- at += s; +- rem -= s; +- } +- break; +- +- case PROTOBUF_C_TYPE_SINT64: +- while (rem > 0) { +- unsigned s = scan_varint(rem, at); +- if (s == 0) { +- PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); +- return FALSE; +- } +- ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); +- at += s; +- rem -= s; +- } +- break; +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_UINT64: +- while (rem > 0) { +- unsigned s = scan_varint(rem, at); +- if (s == 0) { +- PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); +- return FALSE; +- } +- ((int64_t *) array)[count++] = parse_uint64(s, at); +- at += s; +- rem -= s; +- } +- break; +- case PROTOBUF_C_TYPE_BOOL: +- count = rem; +- for (i = 0; i < count; i++) { +- if (at[i] > 1) { +- PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); +- return FALSE; +- } +- ((protobuf_c_boolean *) array)[i] = at[i]; +- } +- break; +- default: +- PROTOBUF_C__ASSERT_NOT_REACHED(); +- } +- *p_n += count; +- return TRUE; +- +-#if !defined(WORDS_BIGENDIAN) +-no_unpacking_needed: +- memcpy(array, at, count * siz); +- *p_n += count; +- return TRUE; +-#endif +-} +- +-static protobuf_c_boolean +-is_packable_type(ProtobufCType type) +-{ +- return +- type != PROTOBUF_C_TYPE_STRING && +- type != PROTOBUF_C_TYPE_BYTES && +- type != PROTOBUF_C_TYPE_MESSAGE; +-} +- +-static protobuf_c_boolean +-parse_member(ScannedMember *scanned_member, +- ProtobufCMessage *message, +- ProtobufCAllocator *allocator) +-{ +- const ProtobufCFieldDescriptor *field = scanned_member->field; +- void *member; +- +- if (field == NULL) { +- ProtobufCMessageUnknownField *ufield = +- message->unknown_fields + +- (message->n_unknown_fields++); +- ufield->tag = scanned_member->tag; +- ufield->wire_type = scanned_member->wire_type; +- ufield->len = scanned_member->len; +- ufield->data = do_alloc(allocator, scanned_member->len); +- if (ufield->data == NULL) +- return FALSE; +- memcpy(ufield->data, scanned_member->data, ufield->len); +- return TRUE; +- } +- member = (char *) message + field->offset; +- switch (field->label) { +- case PROTOBUF_C_LABEL_REQUIRED: +- return parse_required_member(scanned_member, member, +- allocator, TRUE); +- case PROTOBUF_C_LABEL_OPTIONAL: +- return parse_optional_member(scanned_member, member, +- message, allocator); +- case PROTOBUF_C_LABEL_REPEATED: +- if (scanned_member->wire_type == +- PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && +- (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || +- is_packable_type(field->type))) +- { +- return parse_packed_repeated_member(scanned_member, +- member, message); +- } else { +- return parse_repeated_member(scanned_member, +- member, message, +- allocator); +- } +- } +- PROTOBUF_C__ASSERT_NOT_REACHED(); +- return 0; +-} +- +-/** +- * 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). +- */ +-static void +-message_init_generic(const ProtobufCMessageDescriptor *desc, +- ProtobufCMessage *message) +-{ +- unsigned i; +- +- memset(message, 0, desc->sizeof_message); +- message->descriptor = desc; +- for (i = 0; i < desc->n_fields; i++) { +- if (desc->fields[i].default_value != NULL && +- desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) +- { +- void *field = +- STRUCT_MEMBER_P(message, desc->fields[i].offset); +- const void *dv = desc->fields[i].default_value; +- +- switch (desc->fields[i].type) { +- case PROTOBUF_C_TYPE_INT32: +- case PROTOBUF_C_TYPE_SINT32: +- case PROTOBUF_C_TYPE_SFIXED32: +- case PROTOBUF_C_TYPE_UINT32: +- case PROTOBUF_C_TYPE_FIXED32: +- case PROTOBUF_C_TYPE_FLOAT: +- case PROTOBUF_C_TYPE_ENUM: +- memcpy(field, dv, 4); +- break; +- case PROTOBUF_C_TYPE_INT64: +- case PROTOBUF_C_TYPE_SINT64: +- case PROTOBUF_C_TYPE_SFIXED64: +- case PROTOBUF_C_TYPE_UINT64: +- case PROTOBUF_C_TYPE_FIXED64: +- case PROTOBUF_C_TYPE_DOUBLE: +- memcpy(field, dv, 8); +- break; +- case PROTOBUF_C_TYPE_BOOL: +- memcpy(field, dv, sizeof(protobuf_c_boolean)); +- break; +- case PROTOBUF_C_TYPE_BYTES: +- memcpy(field, dv, sizeof(ProtobufCBinaryData)); +- break; +- +- case PROTOBUF_C_TYPE_STRING: +- case PROTOBUF_C_TYPE_MESSAGE: +- /* +- * The next line essentially implements a cast +- * from const, which is totally unavoidable. +- */ +- *(const void **) field = dv; +- break; +- } +- } +- } +-} +- +-/**@}*/ +- +-/* +- * ScannedMember slabs (an unpacking implementation detail). Before doing real +- * unpacking, we first scan through the elements to see how many there are (for +- * repeated fields), and which field to use (for non-repeated fields given +- * twice). +- * +- * In order to avoid allocations for small messages, we keep a stack-allocated +- * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we +- * fill that up, we allocate each slab twice as large as the previous one. +- */ +-#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4 +- +-/* +- * The number of slabs, including the stack-allocated ones; choose the number so +- * that we would overflow if we needed a slab larger than provided. +- */ +-#define MAX_SCANNED_MEMBER_SLAB \ +- (sizeof(unsigned int)*8 - 1 \ +- - 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, +- size_t len, const uint8_t *data) +-{ +- ProtobufCMessage *rv; +- size_t rem = len; +- const uint8_t *at = data; +- const ProtobufCFieldDescriptor *last_field = desc->fields + 0; +- ScannedMember first_member_slab[1 << +- FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; +- +- /* +- * scanned_member_slabs[i] is an array of arrays of ScannedMember. +- * The first slab (scanned_member_slabs[0] is just a pointer to +- * first_member_slab), above. All subsequent slabs will be allocated +- * using the allocator. +- */ +- ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; +- unsigned which_slab = 0; /* the slab we are currently populating */ +- unsigned in_slab_index = 0; /* number of members in the slab */ +- size_t n_unknown = 0; +- unsigned f; +- unsigned j; +- unsigned i_slab; +- unsigned last_field_index = 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__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 +- * provide the function, and (2) descriptors constructed from some other +- * source (most likely, direct construction from the .proto file). +- */ +- if (desc->message_init != NULL) +- protobuf_c_message_init(desc, rv); +- else +- message_init_generic(desc, rv); +- +- while (rem > 0) { +- uint32_t tag; +- ProtobufCWireType wire_type; +- size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); +- const ProtobufCFieldDescriptor *field; +- ScannedMember tmp; +- +- if (used == 0) { +- PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", +- (unsigned) (at - data)); +- goto error_cleanup_during_scan; +- } +- /* +- * \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 = +- int_range_lookup(desc->n_field_ranges, +- desc->field_ranges, +- tag); +- if (field_index < 0) { +- field = NULL; +- n_unknown++; +- } else { +- field = desc->fields + field_index; +- last_field = field; +- last_field_index = field_index; +- } +- } else { +- field = last_field; +- } +- +- if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) +- REQUIRED_FIELD_BITMAP_SET(last_field_index); +- +- at += used; +- rem -= used; +- tmp.tag = tag; +- tmp.wire_type = wire_type; +- tmp.field = field; +- tmp.data = at; +- tmp.length_prefix_len = 0; +- +- switch (wire_type) { +- case PROTOBUF_C_WIRE_TYPE_VARINT: { +- unsigned max_len = rem < 10 ? rem : 10; +- unsigned i; +- +- for (i = 0; i < max_len; i++) +- if ((at[i] & 0x80) == 0) +- break; +- if (i == max_len) { +- PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", +- (unsigned) (at - data)); +- goto error_cleanup_during_scan; +- } +- tmp.len = i + 1; +- break; +- } +- case PROTOBUF_C_WIRE_TYPE_64BIT: +- if (rem < 8) { +- PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", +- (unsigned) (at - data)); +- goto error_cleanup_during_scan; +- } +- tmp.len = 8; +- break; +- case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { +- size_t pref_len; +- +- tmp.len = scan_length_prefixed_data(rem, at, &pref_len); +- if (tmp.len == 0) { +- /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ +- goto error_cleanup_during_scan; +- } +- tmp.length_prefix_len = pref_len; +- break; +- } +- case PROTOBUF_C_WIRE_TYPE_32BIT: +- if (rem < 4) { +- PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", +- (unsigned) (at - data)); +- goto error_cleanup_during_scan; +- } +- tmp.len = 4; +- break; +- default: +- PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", +- wire_type, (unsigned) (at - data)); +- goto error_cleanup_during_scan; +- } +- +- if (in_slab_index == (1U << +- (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) +- { +- size_t size; +- +- in_slab_index = 0; +- if (which_slab == MAX_SCANNED_MEMBER_SLAB) { +- PROTOBUF_C_UNPACK_ERROR("too many fields"); +- goto error_cleanup_during_scan; +- } +- which_slab++; +- size = sizeof(ScannedMember) +- << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); +- scanned_member_slabs[which_slab] = do_alloc(allocator, size); +- if (scanned_member_slabs[which_slab] == NULL) +- goto error_cleanup_during_scan; +- } +- scanned_member_slabs[which_slab][in_slab_index++] = tmp; +- +- if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { +- size_t *n = STRUCT_MEMBER_PTR(size_t, rv, +- field->quantifier_offset); +- if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && +- (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || +- is_packable_type(field->type))) +- { +- size_t count; +- if (!count_packed_elements(field->type, +- tmp.len - +- tmp.length_prefix_len, +- tmp.data + +- tmp.length_prefix_len, +- &count)) +- { +- PROTOBUF_C_UNPACK_ERROR("counting packed elements"); +- goto error_cleanup_during_scan; +- } +- *n += count; +- } else { +- *n += 1; +- } +- } +- +- at += tmp.len; +- rem -= tmp.len; +- } +- +- /* allocate space for repeated fields, also check that all required fields have been set */ +- for (f = 0; f < desc->n_fields; f++) { +- const ProtobufCFieldDescriptor *field = desc->fields + f; +- if (field->label == PROTOBUF_C_LABEL_REPEATED) { +- size_t siz = +- sizeof_elt_in_repeated_array(field->type); +- size_t *n_ptr = +- STRUCT_MEMBER_PTR(size_t, rv, +- field->quantifier_offset); +- if (*n_ptr != 0) { +- unsigned n = *n_ptr; +- *n_ptr = 0; +- assert(rv->descriptor != NULL); +-#define CLEAR_REMAINING_N_PTRS() \ +- for(f++;f < desc->n_fields; f++) \ +- { \ +- field = desc->fields + f; \ +- if (field->label == PROTOBUF_C_LABEL_REPEATED) \ +- STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \ +- } +- void *a = do_alloc(allocator, siz * n); +- if (!a) { +- CLEAR_REMAINING_N_PTRS(); +- goto error_cleanup; +- } +- STRUCT_MEMBER(void *, rv, field->offset) = a; +- } +- } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) { +- if (field->default_value == NULL && +- !REQUIRED_FIELD_BITMAP_IS_SET(f)) +- { +- CLEAR_REMAINING_N_PTRS(); +- PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'", +- desc->name, field->name); +- goto error_cleanup; +- } +- } +- } +-#undef CLEAR_REMAINING_N_PTRS +- +- /* allocate space for unknown fields */ +- if (n_unknown) { +- rv->unknown_fields = do_alloc(allocator, +- n_unknown * sizeof(ProtobufCMessageUnknownField)); +- if (rv->unknown_fields == NULL) +- goto error_cleanup; +- } +- +- /* do real parsing */ +- for (i_slab = 0; i_slab <= which_slab; i_slab++) { +- unsigned max = (i_slab == which_slab) ? +- in_slab_index : (1U << (i_slab + 4)); +- ScannedMember *slab = scanned_member_slabs[i_slab]; +- unsigned j; +- +- for (j = 0; j < max; j++) { +- if (!parse_member(slab + j, rv, allocator)) { +- PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", +- slab->field ? slab->field->name : "*unknown-field*", +- desc->name); +- goto error_cleanup; +- } +- } +- } +- +- /* 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; +-} +- +-void +-protobuf_c_message_free_unpacked(ProtobufCMessage *message, +- ProtobufCAllocator *allocator) +-{ +- const ProtobufCMessageDescriptor *desc = message->descriptor; +- unsigned f; +- +- ASSERT_IS_MESSAGE(message); +- if (allocator == NULL) +- allocator = &protobuf_c__allocator; +- message->descriptor = NULL; +- for (f = 0; f < desc->n_fields; f++) { +- if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { +- size_t n = STRUCT_MEMBER(size_t, +- message, +- desc->fields[f].quantifier_offset); +- void *arr = STRUCT_MEMBER(void *, +- message, +- desc->fields[f].offset); +- +- if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { +- unsigned i; +- for (i = 0; i < n; i++) +- do_free(allocator, ((char **) arr)[i]); +- } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { +- unsigned i; +- for (i = 0; i < n; i++) +- do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); +- } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { +- unsigned i; +- for (i = 0; i < n; i++) +- protobuf_c_message_free_unpacked( +- ((ProtobufCMessage **) arr)[i], +- allocator +- ); +- } +- if (arr != NULL) +- do_free(allocator, arr); +- } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { +- char *str = STRUCT_MEMBER(char *, message, +- desc->fields[f].offset); +- +- if (str && str != desc->fields[f].default_value) +- do_free(allocator, str); +- } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { +- void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, +- desc->fields[f].offset).data; +- const ProtobufCBinaryData *default_bd; +- +- default_bd = desc->fields[f].default_value; +- if (data != NULL && +- (default_bd == NULL || +- default_bd->data != data)) +- { +- do_free(allocator, data); +- } +- } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { +- ProtobufCMessage *sm; +- +- sm = STRUCT_MEMBER(ProtobufCMessage *, message, +- desc->fields[f].offset); +- if (sm && sm != desc->fields[f].default_value) +- protobuf_c_message_free_unpacked(sm, allocator); +- } +- } +- +- for (f = 0; f < message->n_unknown_fields; f++) +- do_free(allocator, message->unknown_fields[f].data); +- if (message->unknown_fields != NULL) +- do_free(allocator, message->unknown_fields); +- +- do_free(allocator, message); +-} +- +-void +-protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, +- void *message) +-{ +- descriptor->message_init((ProtobufCMessage *) (message)); +-} +- +-protobuf_c_boolean +-protobuf_c_message_check(const ProtobufCMessage *message) +-{ +- if (!message || +- !message->descriptor || +- message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) +- { +- 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; +- } +- +- 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; +-} +- +-/* === services === */ +- +-typedef void (*GenericHandler) (void *service, +- const ProtobufCMessage *input, +- ProtobufCClosure closure, +- void *closure_data); +-void +-protobuf_c_service_invoke_internal(ProtobufCService *service, +- unsigned method_index, +- const ProtobufCMessage *input, +- ProtobufCClosure closure, +- void *closure_data) +-{ +- GenericHandler *handlers; +- 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 +- * other memory corruption bugs can cause this assertion too.) +- */ +- assert(method_index < service->descriptor->n_methods); +- +- /* +- * Get the array of virtual methods (which are enumerated by the +- * generated code). +- */ +- handlers = (GenericHandler *) (service + 1); +- +- /* +- * 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); +-} +- +-void +-protobuf_c_service_generated_init(ProtobufCService *service, +- const ProtobufCServiceDescriptor *descriptor, +- ProtobufCServiceDestroy destroy) +-{ +- ASSERT_IS_SERVICE_DESCRIPTOR(descriptor); +- service->descriptor = descriptor; +- service->destroy = destroy; +- service->invoke = protobuf_c_service_invoke_internal; +- memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler)); +-} +- +-void protobuf_c_service_destroy(ProtobufCService *service) +-{ +- service->destroy(service); +-} +- +-/* --- querying the descriptors --- */ +- +-const ProtobufCEnumValue * +-protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, +- const char *name) +-{ +- unsigned start = 0; +- unsigned count = desc->n_value_names; +- +- while (count > 1) { +- unsigned mid = start + count / 2; +- int rv = strcmp(desc->values_by_name[mid].name, name); +- if (rv == 0) +- return desc->values + desc->values_by_name[mid].index; +- else if (rv < 0) { +- count = start + count - (mid + 1); +- start = mid + 1; +- } else +- count = mid - start; +- } +- if (count == 0) +- return NULL; +- if (strcmp(desc->values_by_name[start].name, name) == 0) +- return desc->values + desc->values_by_name[start].index; +- return NULL; +-} +- +-const ProtobufCEnumValue * +-protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, +- int value) +-{ +- int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); +- if (rv < 0) +- return NULL; +- return desc->values + rv; +-} +- +-const ProtobufCFieldDescriptor * +-protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, +- const char *name) +-{ +- unsigned start = 0; +- unsigned count = desc->n_fields; +- const ProtobufCFieldDescriptor *field; +- +- while (count > 1) { +- unsigned mid = start + count / 2; +- int rv; +- field = desc->fields + desc->fields_sorted_by_name[mid]; +- rv = strcmp(field->name, name); +- if (rv == 0) +- return field; +- else if (rv < 0) { +- count = start + count - (mid + 1); +- start = mid + 1; +- } else +- count = mid - start; +- } +- if (count == 0) +- return NULL; +- field = desc->fields + desc->fields_sorted_by_name[start]; +- if (strcmp(field->name, name) == 0) +- return field; +- return NULL; +-} +- +-const ProtobufCFieldDescriptor * +-protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc, +- unsigned value) +-{ +- int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value); +- if (rv < 0) +- return NULL; +- return desc->fields + rv; +-} +- +-const ProtobufCMethodDescriptor * +-protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, +- const char *name) +-{ +- unsigned start = 0; +- unsigned count = desc->n_methods; +- +- while (count > 1) { +- unsigned mid = start + count / 2; +- unsigned mid_index = desc->method_indices_by_name[mid]; +- const char *mid_name = desc->methods[mid_index].name; +- int rv = strcmp(mid_name, name); +- +- if (rv == 0) +- return desc->methods + desc->method_indices_by_name[mid]; +- if (rv < 0) { +- count = start + count - (mid + 1); +- start = mid + 1; +- } else { +- count = mid - start; +- } +- } +- if (count == 0) +- return NULL; +- if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0) +- return desc->methods + desc->method_indices_by_name[start]; +- return NULL; +-} +diff --git a/src/protobuf/google/protobuf-c/protobuf-c.h b/src/protobuf/google/protobuf-c/protobuf-c.h +deleted file mode 100644 +index 593df2d..0000000 +--- a/src/protobuf/google/protobuf-c/protobuf-c.h ++++ /dev/null +@@ -1,1079 +0,0 @@ +-/* +- * 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 +- * met: +- * +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * +- * * Redistributions in binary form must reproduce the above +- * copyright notice, this list of conditions and the following disclaimer +- * in the documentation and/or other materials provided with the +- * distribution. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-/*! \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 +- +-#ifdef __cplusplus +-# define PROTOBUF_C__BEGIN_DECLS extern "C" { +-# define PROTOBUF_C__END_DECLS } +-#else +-# define PROTOBUF_C__BEGIN_DECLS +-# define PROTOBUF_C__END_DECLS +-#endif +- +-PROTOBUF_C__BEGIN_DECLS +- +-#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) +-# ifdef PROTOBUF_C_EXPORT +-# define PROTOBUF_C__API __declspec(dllexport) +-# else +-# define PROTOBUF_C__API __declspec(dllimport) +-# endif +-#else +-# define PROTOBUF_C__API +-#endif +- +-#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 +- +-#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, +- +- /** +- * 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, /**< 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; +- +-/** +- * 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; +- +-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; +- +-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; +-}; +- +-/** +- * Structure for the protobuf `bytes` scalar type. +- * +- * 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. +- */ +-struct ProtobufCBinaryData { +- size_t len; /**< Number of bytes in the `data` field. */ +- uint8_t *data; /**< Data bytes. */ +-}; +- +-/** +- * 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); +-}; +- +-/** +- * 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 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; +-}; +- +-/** +- * Describes an enumeration as a whole, with all of its values. +- */ +-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; +- +- /** Number elements in `values`. */ +- unsigned n_values; +- /** Array of distinct values, sorted by numeric value. */ +- const ProtobufCEnumValue *values; +- +- /** 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; +- +- /** 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; +-}; +- +-/** +- * Represents a single value of an enumeration. +- */ +-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; +-}; +- +-/** +- * 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 requires that the values in the original array are +- * sorted. +- */ +-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 +- * this simple. +- */ +-}; +- +-/** +- * 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(). +- */ +-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; +-}; +- +-/** +- * Describes a message. +- */ +-struct ProtobufCMessageDescriptor { +- /** 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; +- +- /** +- * 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); +- +-PROTOBUF_C__API +-void +-protobuf_c_service_invoke_internal( +- ProtobufCService *service, +- unsigned method_index, +- const ProtobufCMessage *input, +- ProtobufCClosure closure, +- void *closure_data); +- +-/**@}*/ +- +-PROTOBUF_C__END_DECLS +- +-#endif /* PROTOBUF_C_H */ +diff --git a/src/protobuf/protobuf-c/protobuf-c.c b/src/protobuf/protobuf-c/protobuf-c.c +new file mode 100644 +index 0000000..c7fb21d +--- /dev/null ++++ b/src/protobuf/protobuf-c/protobuf-c.c +@@ -0,0 +1,3272 @@ ++/* ++ * 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 ++ * met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/*! \file ++ * Support library for `protoc-c` generated code. ++ * ++ * This file implements the public API used by the code generated ++ * by `protoc-c`. ++ * ++ * \authors Dave Benson and the protobuf-c authors ++ * ++ * \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). ++ * ++ * \todo Use size_t consistently. ++ */ ++ ++#include /* for malloc, free */ ++#include /* for strcmp, strlen, memcpy, memmove, memset */ ++ ++#include "protobuf-c.h" ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) ++ ++/** ++ * \defgroup internal Internal functions and macros ++ * ++ * These are not exported by the library but are useful to developers working ++ * on `libprotobuf-c` itself. ++ */ ++ ++/** ++ * \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) ++ ++#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ ++ 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) ++ ++/**@}*/ ++ ++/* --- version --- */ ++ ++const char * ++protobuf_c_version(void) ++{ ++ return PROTOBUF_C_VERSION; ++} ++ ++uint32_t ++protobuf_c_version_number(void) ++{ ++ return PROTOBUF_C_VERSION_NUMBER; ++} ++ ++/* --- allocator --- */ ++ ++static void * ++system_alloc(void *allocator_data, size_t size) ++{ ++ return malloc(size); ++} ++ ++static void ++system_free(void *allocator_data, void *data) ++{ ++ free(data); ++} ++ ++static inline void * ++do_alloc(ProtobufCAllocator *allocator, size_t size) ++{ ++ return allocator->alloc(allocator->allocator_data, size); ++} ++ ++static inline void ++do_free(ProtobufCAllocator *allocator, void *data) ++{ ++ if (data != NULL) ++ allocator->free(allocator->allocator_data, data); ++} ++ ++/* ++ * 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. ++ */ ++static ProtobufCAllocator protobuf_c__allocator = { ++ .alloc = &system_alloc, ++ .free = &system_free, ++ .allocator_data = NULL, ++}; ++ ++/* === buffer-simple === */ ++ ++void ++protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, ++ size_t len, const uint8_t *data) ++{ ++ ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) 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(allocator, new_alloced); ++ if (!new_data) ++ return; ++ memcpy(new_data, simp->data, simp->len); ++ if (simp->must_free_data) ++ do_free(allocator, simp->data); ++ else ++ simp->must_free_data = TRUE; ++ simp->data = new_data; ++ simp->alloced = new_alloced; ++ } ++ memcpy(simp->data + simp->len, data, len); ++ simp->len = new_len; ++} ++ ++/** ++ * \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) ++{ ++ if (number < (1 << 4)) { ++ return 1; ++ } else if (number < (1 << 11)) { ++ return 2; ++ } else if (number < (1 << 18)) { ++ return 3; ++ } else if (number < (1 << 25)) { ++ return 4; ++ } else { ++ return 5; ++ } ++} ++ ++/** ++ * 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) ++{ ++ if (v < (1 << 7)) { ++ return 1; ++ } else if (v < (1 << 14)) { ++ return 2; ++ } else if (v < (1 << 21)) { ++ return 3; ++ } else if (v < (1 << 28)) { ++ return 4; ++ } else { ++ return 5; ++ } ++} ++ ++/** ++ * 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) ++{ ++ if (v < 0) { ++ return 10; ++ } else if (v < (1 << 7)) { ++ return 1; ++ } else if (v < (1 << 14)) { ++ return 2; ++ } else if (v < (1 << 21)) { ++ return 3; ++ } else if (v < (1 << 28)) { ++ return 4; ++ } else { ++ return 5; ++ } ++} ++ ++/** ++ * 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) ++{ ++ if (v < 0) ++ return ((uint32_t) (-v)) * 2 - 1; ++ else ++ 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) ++{ ++ 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) ++{ ++ uint32_t upper_v = (uint32_t) (v >> 32); ++ ++ if (upper_v == 0) { ++ return uint32_size((uint32_t) v); ++ } else if (upper_v < (1 << 3)) { ++ return 5; ++ } else if (upper_v < (1 << 10)) { ++ return 6; ++ } else if (upper_v < (1 << 17)) { ++ return 7; ++ } else if (upper_v < (1 << 24)) { ++ return 8; ++ } else if (upper_v < (1U << 31)) { ++ return 9; ++ } else { ++ return 10; ++ } ++} ++ ++/** ++ * 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) ++{ ++ if (v < 0) ++ return ((uint64_t) (-v)) * 2 - 1; ++ else ++ 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) ++{ ++ 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, ++ const void *member) ++{ ++ size_t rv = get_tag_size(field->id); ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SINT32: ++ return rv + sint32_size(*(const int32_t *) member); ++ case PROTOBUF_C_TYPE_INT32: ++ return rv + int32_size(*(const uint32_t *) member); ++ case PROTOBUF_C_TYPE_UINT32: ++ return rv + uint32_size(*(const uint32_t *) member); ++ case PROTOBUF_C_TYPE_SINT64: ++ return rv + sint64_size(*(const int64_t *) member); ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ return rv + uint64_size(*(const uint64_t *) member); ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ return rv + 4; ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ return rv + 8; ++ case PROTOBUF_C_TYPE_BOOL: ++ return rv + 1; ++ case PROTOBUF_C_TYPE_FLOAT: ++ return rv + 4; ++ case PROTOBUF_C_TYPE_DOUBLE: ++ return rv + 8; ++ case PROTOBUF_C_TYPE_ENUM: ++ /* \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; ++ size_t len = str ? strlen(str) : 0; ++ return rv + uint32_size(len) + len; ++ } ++ case PROTOBUF_C_TYPE_BYTES: { ++ size_t len = ((const ProtobufCBinaryData *) member)->len; ++ return rv + uint32_size(len) + len; ++ } ++ 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(); ++ 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. ++ * ++ * \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, ++ const void *member) ++{ ++ if (field->type == PROTOBUF_C_TYPE_MESSAGE || ++ field->type == PROTOBUF_C_TYPE_STRING) ++ { ++ const void *ptr = *(const void * const *) member; ++ if (ptr == NULL || ptr == field->default_value) ++ return 0; ++ } else { ++ if (!*has) ++ return 0; ++ } ++ 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, ++ size_t count, const void *member) ++{ ++ size_t header_size; ++ size_t rv = 0; ++ unsigned i; ++ void *array = *(void * const *) member; ++ ++ if (count == 0) ++ return 0; ++ header_size = get_tag_size(field->id); ++ if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) ++ header_size *= count; ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SINT32: ++ for (i = 0; i < count; i++) ++ rv += sint32_size(((int32_t *) array)[i]); ++ break; ++ case PROTOBUF_C_TYPE_INT32: ++ for (i = 0; i < count; i++) ++ rv += int32_size(((uint32_t *) array)[i]); ++ break; ++ case PROTOBUF_C_TYPE_UINT32: ++ case PROTOBUF_C_TYPE_ENUM: ++ for (i = 0; i < count; i++) ++ rv += uint32_size(((uint32_t *) array)[i]); ++ break; ++ case PROTOBUF_C_TYPE_SINT64: ++ for (i = 0; i < count; i++) ++ rv += sint64_size(((int64_t *) array)[i]); ++ break; ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ for (i = 0; i < count; i++) ++ rv += uint64_size(((uint64_t *) array)[i]); ++ break; ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ rv += 4 * count; ++ break; ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ rv += 8 * count; ++ break; ++ case PROTOBUF_C_TYPE_BOOL: ++ rv += count; ++ break; ++ case PROTOBUF_C_TYPE_STRING: ++ for (i = 0; i < count; i++) { ++ size_t len = strlen(((char **) array)[i]); ++ rv += uint32_size(len) + len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_BYTES: ++ for (i = 0; i < count; i++) { ++ size_t len = ((ProtobufCBinaryData *) array)[i].len; ++ rv += uint32_size(len) + len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_MESSAGE: ++ for (i = 0; i < count; i++) { ++ size_t len = protobuf_c_message_get_packed_size( ++ ((ProtobufCMessage **) array)[i]); ++ rv += uint32_size(len) + len; ++ } ++ break; ++ } ++ ++ 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) ++{ ++ return get_tag_size(field->tag) + field->len; ++} ++ ++/**@}*/ ++ ++/* ++ * Calculate the serialized size of the message. ++ */ ++size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) ++{ ++ unsigned i; ++ size_t rv = 0; ++ ++ ASSERT_IS_MESSAGE(message); ++ for (i = 0; i < message->descriptor->n_fields; i++) { ++ const ProtobufCFieldDescriptor *field = ++ message->descriptor->fields + i; ++ const void *member = ++ ((const char *) message) + field->offset; ++ const void *qmember = ++ ((const char *) message) + field->quantifier_offset; ++ ++ if (field->label == PROTOBUF_C_LABEL_REQUIRED) { ++ rv += required_field_get_packed_size(field, member); ++ } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { ++ rv += optional_field_get_packed_size(field, qmember, member); ++ } else { ++ rv += repeated_field_get_packed_size( ++ field, ++ *(const size_t *) qmember, ++ member ++ ); ++ } ++ } ++ for (i = 0; i < message->n_unknown_fields; i++) ++ rv += unknown_field_get_packed_size(&message->unknown_fields[i]); ++ return rv; ++} ++ ++/** ++ * \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) ++{ ++ unsigned rv = 0; ++ ++ if (value >= 0x80) { ++ out[rv++] = value | 0x80; ++ value >>= 7; ++ if (value >= 0x80) { ++ out[rv++] = value | 0x80; ++ value >>= 7; ++ if (value >= 0x80) { ++ out[rv++] = value | 0x80; ++ value >>= 7; ++ if (value >= 0x80) { ++ out[rv++] = value | 0x80; ++ value >>= 7; ++ } ++ } ++ } ++ } ++ /* assert: value<128 */ ++ out[rv++] = value; ++ 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) ++{ ++ if (value < 0) { ++ out[0] = value | 0x80; ++ out[1] = (value >> 7) | 0x80; ++ out[2] = (value >> 14) | 0x80; ++ out[3] = (value >> 21) | 0x80; ++ out[4] = (value >> 28) | 0x80; ++ out[5] = out[6] = out[7] = out[8] = 0xff; ++ out[9] = 0x01; ++ return 10; ++ } else { ++ return uint32_pack(value, 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) ++{ ++ 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) ++{ ++ uint32_t hi = (uint32_t) (value >> 32); ++ uint32_t lo = (uint32_t) value; ++ unsigned rv; ++ ++ if (hi == 0) ++ return uint32_pack((uint32_t) lo, out); ++ out[0] = (lo) | 0x80; ++ out[1] = (lo >> 7) | 0x80; ++ out[2] = (lo >> 14) | 0x80; ++ out[3] = (lo >> 21) | 0x80; ++ if (hi < 8) { ++ out[4] = (hi << 4) | (lo >> 28); ++ return 5; ++ } else { ++ out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; ++ hi >>= 3; ++ } ++ rv = 5; ++ while (hi >= 128) { ++ out[rv++] = hi | 0x80; ++ hi >>= 7; ++ } ++ out[rv++] = hi; ++ 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) ++{ ++ 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) ++{ ++#if !defined(WORDS_BIGENDIAN) ++ memcpy(out, &value, 4); ++#else ++ uint8_t *buf = out; ++ ++ buf[0] = value; ++ buf[1] = value >> 8; ++ buf[2] = value >> 16; ++ buf[3] = value >> 24; ++#endif ++ return 4; ++} ++ ++/** ++ * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire ++ * types fixed64, sfixed64, double. Similar to "htole64". ++ * ++ * \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) ++{ ++#if !defined(WORDS_BIGENDIAN) ++ memcpy(out, &value, 8); ++#else ++ fixed32_pack(value, out); ++ fixed32_pack(value >> 32, ((char *) out) + 4); ++#endif ++ return 8; ++} ++ ++/** ++ * Pack a boolean value as an integer and return the number of bytes written. ++ * ++ * \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 ? 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 ++ * 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) ++{ ++ if (str == NULL) { ++ out[0] = 0; ++ return 1; ++ } else { ++ size_t len = strlen(str); ++ size_t rv = uint32_pack(len, out); ++ memcpy(out + rv, str, len); ++ return rv + len; ++ } ++} ++ ++/** ++ * 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) ++{ ++ size_t len = bd->len; ++ size_t rv = uint32_pack(len, out); ++ memcpy(out + rv, bd->data, len); ++ 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) ++{ ++ if (message == NULL) { ++ out[0] = 0; ++ return 1; ++ } else { ++ size_t rv = protobuf_c_message_pack(message, out + 1); ++ uint32_t rv_packed_size = uint32_size(rv); ++ if (rv_packed_size != 1) ++ memmove(out + rv_packed_size, out + 1, rv); ++ return uint32_pack(rv, out) + rv; ++ } ++} ++ ++/** ++ * 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) ++{ ++ if (id < (1 << (32 - 3))) ++ return uint32_pack(id << 3, out); ++ else ++ 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) ++{ ++ size_t rv = tag_pack(field->id, out); ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SINT32: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ return rv + sint32_pack(*(const int32_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_INT32: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ return rv + int32_pack(*(const uint32_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_UINT32: ++ case PROTOBUF_C_TYPE_ENUM: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ return rv + uint32_pack(*(const uint32_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_SINT64: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ return rv + sint64_pack(*(const int64_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ return rv + uint64_pack(*(const uint64_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; ++ return rv + fixed32_pack(*(const uint32_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; ++ return rv + fixed64_pack(*(const uint64_t *) member, out + rv); ++ case PROTOBUF_C_TYPE_BOOL: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); ++ case PROTOBUF_C_TYPE_STRING: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ return rv + string_pack(*(char *const *) member, out + rv); ++ 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_MESSAGE: ++ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); ++ } ++ 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, ++ const void *member, uint8_t *out) ++{ ++ if (field->type == PROTOBUF_C_TYPE_MESSAGE || ++ field->type == PROTOBUF_C_TYPE_STRING) ++ { ++ const void *ptr = *(const void * const *) member; ++ if (ptr == NULL || ptr == field->default_value) ++ return 0; ++ } else { ++ if (!*has) ++ return 0; ++ } ++ return required_field_pack(field, member, out); ++} ++ ++/** ++ * 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) ++{ ++ switch (type) { ++ case PROTOBUF_C_TYPE_SINT32: ++ case PROTOBUF_C_TYPE_INT32: ++ case PROTOBUF_C_TYPE_UINT32: ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ case PROTOBUF_C_TYPE_ENUM: ++ return 4; ++ case PROTOBUF_C_TYPE_SINT64: ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ return 8; ++ case PROTOBUF_C_TYPE_BOOL: ++ return sizeof(protobuf_c_boolean); ++ case PROTOBUF_C_TYPE_STRING: ++ case PROTOBUF_C_TYPE_MESSAGE: ++ return sizeof(void *); ++ case PROTOBUF_C_TYPE_BYTES: ++ return sizeof(ProtobufCBinaryData); ++ } ++ 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) ++{ ++#if !defined(WORDS_BIGENDIAN) ++ memcpy(out, in, n * 4); ++#else ++ unsigned i; ++ const uint32_t *ini = in; ++ for (i = 0; i < n; i++) ++ fixed32_pack(ini[i], (uint32_t *) out + i); ++#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) ++{ ++#if !defined(WORDS_BIGENDIAN) ++ memcpy(out, in, n * 8); ++#else ++ unsigned i; ++ const uint64_t *ini = in; ++ for (i = 0; i < n; i++) ++ fixed64_pack(ini[i], (uint64_t *) out + i); ++#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) ++{ ++ if (type == PROTOBUF_C_TYPE_SFIXED32 || ++ type == PROTOBUF_C_TYPE_FIXED32 || ++ type == PROTOBUF_C_TYPE_FLOAT) ++ { ++ return 4; ++ } ++ if (type == PROTOBUF_C_TYPE_SFIXED64 || ++ type == PROTOBUF_C_TYPE_FIXED64 || ++ type == PROTOBUF_C_TYPE_DOUBLE) ++ { ++ return 8; ++ } ++ 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) ++{ ++ void *array = *(void * const *) member; ++ unsigned i; ++ ++ if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { ++ unsigned header_len; ++ unsigned len_start; ++ unsigned min_length; ++ unsigned payload_len; ++ unsigned length_size_min; ++ unsigned actual_length_size; ++ uint8_t *payload_at; ++ ++ if (count == 0) ++ return 0; ++ header_len = tag_pack(field->id, out); ++ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ len_start = header_len; ++ min_length = get_type_min_size(field->type) * count; ++ length_size_min = uint32_size(min_length); ++ header_len += length_size_min; ++ payload_at = out + header_len; ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ copy_to_little_endian_32(payload_at, array, count); ++ payload_at += count * 4; ++ break; ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ copy_to_little_endian_64(payload_at, array, count); ++ payload_at += count * 8; ++ break; ++ case PROTOBUF_C_TYPE_INT32: { ++ const int32_t *arr = (const int32_t *) array; ++ for (i = 0; i < count; i++) ++ payload_at += int32_pack(arr[i], payload_at); ++ break; ++ } ++ case PROTOBUF_C_TYPE_SINT32: { ++ const int32_t *arr = (const int32_t *) array; ++ for (i = 0; i < count; i++) ++ payload_at += sint32_pack(arr[i], payload_at); ++ break; ++ } ++ case PROTOBUF_C_TYPE_SINT64: { ++ const int64_t *arr = (const int64_t *) array; ++ for (i = 0; i < count; i++) ++ payload_at += sint64_pack(arr[i], payload_at); ++ break; ++ } ++ case PROTOBUF_C_TYPE_ENUM: ++ case PROTOBUF_C_TYPE_UINT32: { ++ const uint32_t *arr = (const uint32_t *) array; ++ for (i = 0; i < count; i++) ++ payload_at += uint32_pack(arr[i], payload_at); ++ break; ++ } ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: { ++ const uint64_t *arr = (const uint64_t *) array; ++ for (i = 0; i < count; i++) ++ payload_at += uint64_pack(arr[i], payload_at); ++ break; ++ } ++ case PROTOBUF_C_TYPE_BOOL: { ++ const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; ++ for (i = 0; i < count; i++) ++ payload_at += boolean_pack(arr[i], payload_at); ++ break; ++ } ++ default: ++ PROTOBUF_C__ASSERT_NOT_REACHED(); ++ } ++ ++ payload_len = payload_at - (out + header_len); ++ actual_length_size = uint32_size(payload_len); ++ if (length_size_min != actual_length_size) { ++ assert(actual_length_size == length_size_min + 1); ++ memmove(out + header_len + 1, out + header_len, ++ payload_len); ++ header_len++; ++ } ++ uint32_pack(payload_len, out + len_start); ++ return header_len + payload_len; ++ } else { ++ /* 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 = (char *)array + siz; ++ } ++ return rv; ++ } ++} ++ ++static size_t ++unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) ++{ ++ size_t rv = tag_pack(field->tag, out); ++ out[0] |= field->wire_type; ++ memcpy(out + rv, field->data, field->len); ++ return rv + field->len; ++} ++ ++/**@}*/ ++ ++size_t ++protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) ++{ ++ unsigned i; ++ size_t rv = 0; ++ ++ ASSERT_IS_MESSAGE(message); ++ for (i = 0; i < message->descriptor->n_fields; i++) { ++ const ProtobufCFieldDescriptor *field = ++ message->descriptor->fields + i; ++ const void *member = ((const char *) message) + field->offset; ++ ++ /* ++ * It doesn't hurt to compute qmember (a pointer to the ++ * quantifier field of the structure), but the pointer is only ++ * valid if the field is: ++ * - a repeated field, or ++ * - an optional field that isn't a pointer type ++ * (Meaning: not a message or a string). ++ */ ++ const void *qmember = ++ ((const char *) message) + field->quantifier_offset; ++ ++ if (field->label == PROTOBUF_C_LABEL_REQUIRED) { ++ rv += required_field_pack(field, member, out + rv); ++ } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { ++ /* ++ * Note that qmember is bogus for strings and messages, ++ * but it isn't used. ++ */ ++ rv += optional_field_pack(field, qmember, member, out + rv); ++ } else { ++ rv += repeated_field_pack(field, *(const size_t *) qmember, ++ member, out + rv); ++ } ++ } ++ for (i = 0; i < message->n_unknown_fields; i++) ++ rv += unknown_field_pack(&message->unknown_fields[i], out + rv); ++ return rv; ++} ++ ++/** ++ * \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) ++{ ++ size_t rv; ++ uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; ++ ++ rv = tag_pack(field->id, scratch); ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SINT32: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ rv += sint32_pack(*(const int32_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_INT32: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ rv += int32_pack(*(const uint32_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_UINT32: ++ case PROTOBUF_C_TYPE_ENUM: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ rv += uint32_pack(*(const uint32_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_SINT64: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ rv += sint64_pack(*(const int64_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ rv += uint64_pack(*(const uint64_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; ++ rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; ++ rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_BOOL: ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; ++ rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ break; ++ case PROTOBUF_C_TYPE_STRING: { ++ const char *str = *(char *const *) member; ++ size_t sublen = str ? strlen(str) : 0; ++ ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ rv += uint32_pack(sublen, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ buffer->append(buffer, sublen, (const uint8_t *) str); ++ rv += sublen; ++ break; ++ } ++ case PROTOBUF_C_TYPE_BYTES: { ++ const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); ++ size_t sublen = bd->len; ++ ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ rv += uint32_pack(sublen, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ buffer->append(buffer, sublen, bd->data); ++ rv += sublen; ++ break; ++ } ++ case PROTOBUF_C_TYPE_MESSAGE: { ++ uint8_t simple_buffer_scratch[256]; ++ size_t sublen; ++ const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; ++ ProtobufCBufferSimple simple_buffer = ++ PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch); ++ ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ if (msg == NULL) ++ sublen = 0; ++ else ++ sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); ++ rv += uint32_pack(sublen, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ buffer->append(buffer, sublen, simple_buffer.data); ++ rv += sublen; ++ PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); ++ break; ++ } ++ default: ++ 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, ++ const void *member, ProtobufCBuffer *buffer) ++{ ++ if (field->type == PROTOBUF_C_TYPE_MESSAGE || ++ field->type == PROTOBUF_C_TYPE_STRING) ++ { ++ const void *ptr = *(const void *const *) member; ++ if (ptr == NULL || ptr == field->default_value) ++ return 0; ++ } else { ++ if (!*has) ++ return 0; ++ } ++ 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) ++{ ++ unsigned rv = 0; ++ unsigned i; ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ return count * 4; ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ return count * 8; ++ case PROTOBUF_C_TYPE_INT32: { ++ const int32_t *arr = (const int32_t *) array; ++ for (i = 0; i < count; i++) ++ rv += int32_size(arr[i]); ++ break; ++ } ++ case PROTOBUF_C_TYPE_SINT32: { ++ const int32_t *arr = (const int32_t *) array; ++ for (i = 0; i < count; i++) ++ rv += sint32_size(arr[i]); ++ break; ++ } ++ case PROTOBUF_C_TYPE_ENUM: ++ case PROTOBUF_C_TYPE_UINT32: { ++ const uint32_t *arr = (const uint32_t *) array; ++ for (i = 0; i < count; i++) ++ rv += uint32_size(arr[i]); ++ break; ++ } ++ case PROTOBUF_C_TYPE_SINT64: { ++ const int64_t *arr = (const int64_t *) array; ++ for (i = 0; i < count; i++) ++ rv += sint64_size(arr[i]); ++ break; ++ } ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: { ++ const uint64_t *arr = (const uint64_t *) array; ++ for (i = 0; i < count; i++) ++ rv += uint64_size(arr[i]); ++ break; ++ } ++ case PROTOBUF_C_TYPE_BOOL: ++ return count; ++ default: ++ 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, ++ ProtobufCBuffer *buffer) ++{ ++ uint8_t scratch[16]; ++ size_t rv = 0; ++ unsigned i; ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++#if !defined(WORDS_BIGENDIAN) ++ rv = count * 4; ++ goto no_packing_needed; ++#else ++ for (i = 0; i < count; i++) { ++ unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++#endif ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++#if !defined(WORDS_BIGENDIAN) ++ rv = count * 8; ++ goto no_packing_needed; ++#else ++ for (i = 0; i < count; i++) { ++ unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++#endif ++ case PROTOBUF_C_TYPE_INT32: ++ for (i = 0; i < count; i++) { ++ unsigned len = int32_pack(((int32_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_SINT32: ++ for (i = 0; i < count; i++) { ++ unsigned len = sint32_pack(((int32_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_ENUM: ++ case PROTOBUF_C_TYPE_UINT32: ++ for (i = 0; i < count; i++) { ++ unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_SINT64: ++ for (i = 0; i < count; i++) { ++ unsigned len = sint64_pack(((int64_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ for (i = 0; i < count; i++) { ++ unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ break; ++ case PROTOBUF_C_TYPE_BOOL: ++ for (i = 0; i < count; i++) { ++ unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); ++ buffer->append(buffer, len, scratch); ++ rv += len; ++ } ++ return count; ++ default: ++ PROTOBUF_C__ASSERT_NOT_REACHED(); ++ } ++ return rv; ++ ++no_packing_needed: ++ buffer->append(buffer, rv, array); ++ return rv; ++} ++ ++static size_t ++repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, ++ unsigned count, const void *member, ++ ProtobufCBuffer *buffer) ++{ ++ char *array = *(char * const *) member; ++ ++ if (count == 0) ++ return 0; ++ 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); ++ size_t tmp; ++ ++ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; ++ rv += uint32_pack(payload_len, scratch + rv); ++ buffer->append(buffer, rv, scratch); ++ tmp = pack_buffer_packed_payload(field, count, array, buffer); ++ assert(tmp == payload_len); ++ return rv + payload_len; ++ } else { ++ size_t siz; ++ unsigned i; ++ /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ ++ unsigned rv = 0; ++ ++ siz = sizeof_elt_in_repeated_array(field->type); ++ for (i = 0; i < count; i++) { ++ rv += required_field_pack_to_buffer(field, array, buffer); ++ array += siz; ++ } ++ return rv; ++ } ++} ++ ++static size_t ++unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, ++ ProtobufCBuffer *buffer) ++{ ++ uint8_t header[MAX_UINT64_ENCODED_SIZE]; ++ size_t rv = tag_pack(field->tag, header); ++ ++ header[0] |= field->wire_type; ++ buffer->append(buffer, rv, header); ++ buffer->append(buffer, field->len, field->data); ++ return rv + field->len; ++} ++ ++/**@}*/ ++ ++size_t ++protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, ++ ProtobufCBuffer *buffer) ++{ ++ unsigned i; ++ size_t rv = 0; ++ ++ ASSERT_IS_MESSAGE(message); ++ for (i = 0; i < message->descriptor->n_fields; i++) { ++ const ProtobufCFieldDescriptor *field = ++ message->descriptor->fields + i; ++ const void *member = ++ ((const char *) message) + field->offset; ++ const void *qmember = ++ ((const char *) message) + field->quantifier_offset; ++ ++ if (field->label == PROTOBUF_C_LABEL_REQUIRED) { ++ rv += required_field_pack_to_buffer(field, member, buffer); ++ } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { ++ rv += optional_field_pack_to_buffer( ++ field, ++ qmember, ++ member, ++ buffer ++ ); ++ } else { ++ rv += repeated_field_pack_to_buffer( ++ field, ++ *(const size_t *) qmember, ++ member, ++ buffer ++ ); ++ } ++ } ++ for (i = 0; i < message->n_unknown_fields; i++) ++ rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer); ++ ++ return rv; ++} ++ ++/** ++ * \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) ++{ ++ unsigned n; ++ unsigned start; ++ ++ if (n_ranges == 0) ++ return -1; ++ start = 0; ++ n = n_ranges; ++ while (n > 1) { ++ unsigned mid = start + n / 2; ++ ++ if (value < ranges[mid].start_value) { ++ n = mid - start; ++ } else if (value >= ranges[mid].start_value + ++ (int) (ranges[mid + 1].orig_index - ++ ranges[mid].orig_index)) ++ { ++ unsigned new_start = mid + 1; ++ n = start + n - new_start; ++ start = new_start; ++ } else ++ return (value - ranges[mid].start_value) + ++ ranges[mid].orig_index; ++ } ++ if (n > 0) { ++ unsigned start_orig_index = ranges[start].orig_index; ++ unsigned range_size = ++ ranges[start + 1].orig_index - start_orig_index; ++ ++ if (ranges[start].start_value <= value && ++ value < (int) (ranges[start].start_value + range_size)) ++ { ++ return (value - ranges[start].start_value) + ++ start_orig_index; ++ } ++ } ++ return -1; ++} ++ ++static size_t ++parse_tag_and_wiretype(size_t len, ++ const uint8_t *data, ++ uint32_t *tag_out, ++ ProtobufCWireType *wiretype_out) ++{ ++ unsigned max_rv = len > 5 ? 5 : len; ++ uint32_t tag = (data[0] & 0x7f) >> 3; ++ unsigned shift = 4; ++ unsigned rv; ++ ++ *wiretype_out = data[0] & 7; ++ if ((data[0] & 0x80) == 0) { ++ *tag_out = tag; ++ return 1; ++ } ++ for (rv = 1; rv < max_rv; rv++) { ++ if (data[rv] & 0x80) { ++ tag |= (data[rv] & 0x7f) << shift; ++ shift += 7; ++ } else { ++ tag |= data[rv] << shift; ++ *tag_out = tag; ++ return rv + 1; ++ } ++ } ++ return 0; /* error: bad header */ ++} ++ ++/* sizeof(ScannedMember) must be <= (1< len) { ++ PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); ++ return 0; ++ } ++ return hdr_len + val; ++} ++ ++static size_t ++max_b128_numbers(size_t len, const uint8_t *data) ++{ ++ size_t rv = 0; ++ while (len--) ++ if ((*data++ & 0x80) == 0) ++ ++rv; ++ return rv; ++} ++ ++/**@}*/ ++ ++/** ++ * Merge earlier message into a latter message. ++ * ++ * For numeric types and strings, if the same value appears multiple ++ * times, the parser accepts the last value it sees. For embedded ++ * message fields, the parser merges multiple instances of the same ++ * field. That is, all singular scalar fields in the latter instance ++ * replace those in the former, singular embedded messages are merged, ++ * and repeated fields are concatenated. ++ * ++ * The earlier message should be freed after calling this function, as ++ * some of its fields may have been reused and changed to their default ++ * values during the merge. ++ */ ++static protobuf_c_boolean ++merge_messages(ProtobufCMessage *earlier_msg, ++ ProtobufCMessage *latter_msg, ++ ProtobufCAllocator *allocator) ++{ ++ unsigned i; ++ const ProtobufCFieldDescriptor *fields = ++ earlier_msg->descriptor->fields; ++ for (i = 0; i < latter_msg->descriptor->n_fields; i++) { ++ if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { ++ size_t *n_earlier = ++ STRUCT_MEMBER_PTR(size_t, earlier_msg, ++ fields[i].quantifier_offset); ++ uint8_t **p_earlier = ++ STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, ++ fields[i].offset); ++ size_t *n_latter = ++ STRUCT_MEMBER_PTR(size_t, latter_msg, ++ fields[i].quantifier_offset); ++ uint8_t **p_latter = ++ STRUCT_MEMBER_PTR(uint8_t *, latter_msg, ++ fields[i].offset); ++ ++ if (*n_earlier > 0) { ++ if (*n_latter > 0) { ++ /* Concatenate the repeated field */ ++ size_t el_size = ++ sizeof_elt_in_repeated_array(fields[i].type); ++ uint8_t *new_field; ++ ++ new_field = do_alloc(allocator, ++ (*n_earlier + *n_latter) * el_size); ++ if (!new_field) ++ return FALSE; ++ ++ memcpy(new_field, *p_earlier, ++ *n_earlier * el_size); ++ memcpy(new_field + ++ *n_earlier * el_size, ++ *p_latter, ++ *n_latter * el_size); ++ ++ do_free(allocator, *p_latter); ++ do_free(allocator, *p_earlier); ++ *p_latter = new_field; ++ *n_latter = *n_earlier + *n_latter; ++ } else { ++ /* Zero copy the repeated field from the earlier message */ ++ *n_latter = *n_earlier; ++ *p_latter = *p_earlier; ++ } ++ /* Make sure the field does not get double freed */ ++ *n_earlier = 0; ++ *p_earlier = 0; ++ } ++ } else if (fields[i].type == PROTOBUF_C_TYPE_MESSAGE) { ++ ProtobufCMessage **em = ++ STRUCT_MEMBER_PTR(ProtobufCMessage *, ++ earlier_msg, ++ fields[i].offset); ++ ProtobufCMessage **lm = ++ STRUCT_MEMBER_PTR(ProtobufCMessage *, ++ latter_msg, ++ fields[i].offset); ++ if (*em != NULL) { ++ if (*lm != NULL) { ++ if (!merge_messages ++ (*em, *lm, allocator)) ++ return FALSE; ++ } else { ++ /* Zero copy the optional message */ ++ assert(fields[i].label == ++ PROTOBUF_C_LABEL_OPTIONAL); ++ *lm = *em; ++ *em = NULL; ++ } ++ } ++ } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL) { ++ size_t el_size = 0; ++ protobuf_c_boolean need_to_merge = FALSE; ++ void *earlier_elem = ++ STRUCT_MEMBER_P(earlier_msg, fields[i].offset); ++ void *latter_elem = ++ STRUCT_MEMBER_P(latter_msg, fields[i].offset); ++ const void *def_val = fields[i].default_value; ++ ++ switch (fields[i].type) { ++ case PROTOBUF_C_TYPE_BYTES: { ++ el_size = sizeof(ProtobufCBinaryData); ++ uint8_t *e_data = ++ ((ProtobufCBinaryData *) earlier_elem)->data; ++ uint8_t *l_data = ++ ((ProtobufCBinaryData *) latter_elem)->data; ++ const ProtobufCBinaryData *d_bd = ++ (ProtobufCBinaryData *) def_val; ++ ++ need_to_merge = ++ (e_data != NULL && ++ (d_bd != NULL && ++ e_data != d_bd->data)) && ++ (l_data == NULL || ++ (d_bd != NULL && ++ l_data == d_bd->data)); ++ break; ++ } ++ case PROTOBUF_C_TYPE_STRING: { ++ el_size = sizeof(char *); ++ char *e_str = *(char **) earlier_elem; ++ char *l_str = *(char **) latter_elem; ++ const char *d_str = def_val; ++ ++ need_to_merge = e_str != d_str && l_str == d_str; ++ break; ++ } ++ default: { ++ el_size = sizeof_elt_in_repeated_array(fields[i].type); ++ ++ need_to_merge = ++ STRUCT_MEMBER(protobuf_c_boolean, ++ earlier_msg, ++ fields[i].quantifier_offset) && ++ !STRUCT_MEMBER(protobuf_c_boolean, ++ latter_msg, ++ fields[i].quantifier_offset); ++ break; ++ } ++ } ++ ++ if (need_to_merge) { ++ memcpy(latter_elem, earlier_elem, el_size); ++ /* ++ * Reset the element from the old message to 0 ++ * to make sure earlier message deallocation ++ * doesn't corrupt zero-copied data in the new ++ * message, earlier message will be freed after ++ * this function is called anyway ++ */ ++ memset(earlier_elem, 0, el_size); ++ ++ if (fields[i].quantifier_offset != 0) { ++ /* Set the has field, if applicable */ ++ STRUCT_MEMBER(protobuf_c_boolean, ++ latter_msg, ++ fields[i]. ++ quantifier_offset) = TRUE; ++ STRUCT_MEMBER(protobuf_c_boolean, ++ earlier_msg, ++ fields[i]. ++ quantifier_offset) = FALSE; ++ } ++ } ++ } ++ } ++ return TRUE; ++} ++ ++/** ++ * 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) ++{ ++ switch (type) { ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ if (len % 4 != 0) { ++ PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); ++ return FALSE; ++ } ++ *count_out = len / 4; ++ return TRUE; ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ if (len % 8 != 0) { ++ PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); ++ return FALSE; ++ } ++ *count_out = len / 8; ++ return TRUE; ++ case PROTOBUF_C_TYPE_INT32: ++ case PROTOBUF_C_TYPE_SINT32: ++ case PROTOBUF_C_TYPE_ENUM: ++ case PROTOBUF_C_TYPE_UINT32: ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_SINT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ *count_out = max_b128_numbers(len, data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_BOOL: ++ *count_out = len; ++ return TRUE; ++ case PROTOBUF_C_TYPE_STRING: ++ case PROTOBUF_C_TYPE_BYTES: ++ case PROTOBUF_C_TYPE_MESSAGE: ++ default: ++ PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); ++ return FALSE; ++ } ++} ++ ++static inline uint32_t ++parse_uint32(unsigned len, const uint8_t *data) ++{ ++ uint32_t rv = data[0] & 0x7f; ++ if (len > 1) { ++ rv |= ((uint32_t) (data[1] & 0x7f) << 7); ++ if (len > 2) { ++ rv |= ((uint32_t) (data[2] & 0x7f) << 14); ++ if (len > 3) { ++ rv |= ((uint32_t) (data[3] & 0x7f) << 21); ++ if (len > 4) ++ rv |= ((uint32_t) (data[4]) << 28); ++ } ++ } ++ } ++ return rv; ++} ++ ++static inline uint32_t ++parse_int32(unsigned len, const uint8_t *data) ++{ ++ return parse_uint32(len, data); ++} ++ ++static inline int32_t ++unzigzag32(uint32_t v) ++{ ++ if (v & 1) ++ return -(v >> 1) - 1; ++ else ++ return v >> 1; ++} ++ ++static inline uint32_t ++parse_fixed_uint32(const uint8_t *data) ++{ ++#if !defined(WORDS_BIGENDIAN) ++ uint32_t t; ++ memcpy(&t, data, 4); ++ return t; ++#else ++ return data[0] | ++ ((uint32_t) (data[1]) << 8) | ++ ((uint32_t) (data[2]) << 16) | ++ ((uint32_t) (data[3]) << 24); ++#endif ++} ++ ++static uint64_t ++parse_uint64(unsigned len, const uint8_t *data) ++{ ++ unsigned shift, i; ++ uint64_t rv; ++ ++ if (len < 5) ++ return parse_uint32(len, data); ++ rv = ((uint64_t) (data[0] & 0x7f)) | ++ ((uint64_t) (data[1] & 0x7f) << 7) | ++ ((uint64_t) (data[2] & 0x7f) << 14) | ++ ((uint64_t) (data[3] & 0x7f) << 21); ++ shift = 28; ++ for (i = 4; i < len; i++) { ++ rv |= (((uint64_t) (data[i] & 0x7f)) << shift); ++ shift += 7; ++ } ++ return rv; ++} ++ ++static inline int64_t ++unzigzag64(uint64_t v) ++{ ++ if (v & 1) ++ return -(v >> 1) - 1; ++ else ++ return v >> 1; ++} ++ ++static inline uint64_t ++parse_fixed_uint64(const uint8_t *data) ++{ ++#if !defined(WORDS_BIGENDIAN) ++ uint64_t t; ++ memcpy(&t, data, 8); ++ return t; ++#else ++ return (uint64_t) parse_fixed_uint32(data) | ++ (((uint64_t) parse_fixed_uint32(data + 4)) << 32); ++#endif ++} ++ ++static protobuf_c_boolean ++parse_boolean(unsigned len, const uint8_t *data) ++{ ++ unsigned i; ++ for (i = 0; i < len; i++) ++ if (data[i] & 0x7f) ++ return TRUE; ++ return FALSE; ++} ++ ++static protobuf_c_boolean ++parse_required_member(ScannedMember *scanned_member, ++ void *member, ++ ProtobufCAllocator *allocator, ++ protobuf_c_boolean maybe_clear) ++{ ++ unsigned len = scanned_member->len; ++ const uint8_t *data = scanned_member->data; ++ ProtobufCWireType wire_type = scanned_member->wire_type; ++ ++ switch (scanned_member->field->type) { ++ case PROTOBUF_C_TYPE_INT32: ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) ++ return FALSE; ++ *(uint32_t *) member = parse_int32(len, data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_UINT32: ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) ++ return FALSE; ++ *(uint32_t *) member = parse_uint32(len, data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_SINT32: ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) ++ return FALSE; ++ *(int32_t *) member = unzigzag32(parse_uint32(len, data)); ++ 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 FALSE; ++ *(uint32_t *) member = parse_fixed_uint32(data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) ++ return FALSE; ++ *(uint64_t *) member = parse_uint64(len, data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_SINT64: ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) ++ return FALSE; ++ *(int64_t *) member = unzigzag64(parse_uint64(len, data)); ++ 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 FALSE; ++ *(uint64_t *) member = parse_fixed_uint64(data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_BOOL: ++ *(protobuf_c_boolean *) member = parse_boolean(len, data); ++ return TRUE; ++ case PROTOBUF_C_TYPE_ENUM: ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) ++ return FALSE; ++ *(uint32_t *) member = parse_uint32(len, data); ++ 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 FALSE; ++ ++ if (maybe_clear && *pstr != NULL) { ++ const char *def = scanned_member->field->default_value; ++ if (*pstr != NULL && *pstr != def) ++ do_free(allocator, *pstr); ++ } ++ *pstr = do_alloc(allocator, len - pref_len + 1); ++ if (*pstr == NULL) ++ return FALSE; ++ memcpy(*pstr, data + pref_len, len - pref_len); ++ (*pstr)[len - pref_len] = 0; ++ return TRUE; ++ } ++ case PROTOBUF_C_TYPE_BYTES: { ++ ProtobufCBinaryData *bd = member; ++ const ProtobufCBinaryData *def_bd; ++ unsigned pref_len = scanned_member->length_prefix_len; ++ ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) ++ return FALSE; ++ ++ def_bd = scanned_member->field->default_value; ++ if (maybe_clear && ++ bd->data != NULL && ++ (def_bd == NULL || bd->data != def_bd->data)) ++ { ++ do_free(allocator, bd->data); ++ } ++ if (len - pref_len > 0) { ++ bd->data = do_alloc(allocator, len - pref_len); ++ if (bd->data == NULL) ++ return FALSE; ++ memcpy(bd->data, data + pref_len, len - pref_len); ++ } ++ bd->len = len - pref_len; ++ return TRUE; ++ } ++ case PROTOBUF_C_TYPE_MESSAGE: { ++ ProtobufCMessage **pmessage = member; ++ ProtobufCMessage *subm; ++ const ProtobufCMessage *def_mess; ++ protobuf_c_boolean merge_successful = TRUE; ++ unsigned pref_len = scanned_member->length_prefix_len; ++ ++ if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) ++ return FALSE; ++ ++ def_mess = scanned_member->field->default_value; ++ subm = protobuf_c_message_unpack(scanned_member->field->descriptor, ++ allocator, ++ len - pref_len, ++ data + pref_len); ++ ++ if (maybe_clear && ++ *pmessage != NULL && ++ *pmessage != def_mess) ++ { ++ if (subm != NULL) ++ merge_successful = merge_messages(*pmessage, subm, allocator); ++ /* Delete the previous message */ ++ protobuf_c_message_free_unpacked(*pmessage, allocator); ++ } ++ *pmessage = subm; ++ if (subm == NULL || !merge_successful) ++ return FALSE; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ ++static protobuf_c_boolean ++parse_optional_member(ScannedMember *scanned_member, ++ void *member, ++ ProtobufCMessage *message, ++ ProtobufCAllocator *allocator) ++{ ++ if (!parse_required_member(scanned_member, member, allocator, TRUE)) ++ return FALSE; ++ if (scanned_member->field->quantifier_offset != 0) ++ STRUCT_MEMBER(protobuf_c_boolean, ++ message, ++ scanned_member->field->quantifier_offset) = TRUE; ++ return TRUE; ++} ++ ++static protobuf_c_boolean ++parse_repeated_member(ScannedMember *scanned_member, ++ void *member, ++ ProtobufCMessage *message, ++ ProtobufCAllocator *allocator) ++{ ++ 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; ++ ++ if (!parse_required_member(scanned_member, array + siz * (*p_n), ++ allocator, FALSE)) ++ { ++ return FALSE; ++ } ++ *p_n += 1; ++ return TRUE; ++} ++ ++static unsigned ++scan_varint(unsigned len, const uint8_t *data) ++{ ++ unsigned i; ++ if (len > 10) ++ len = 10; ++ for (i = 0; i < len; i++) ++ if ((data[i] & 0x80) == 0) ++ break; ++ if (i == len) ++ return 0; ++ return i + 1; ++} ++ ++static protobuf_c_boolean ++parse_packed_repeated_member(ScannedMember *scanned_member, ++ void *member, ++ ProtobufCMessage *message) ++{ ++ 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); ++ 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; ++ unsigned i; ++ ++ switch (field->type) { ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ count = (scanned_member->len - scanned_member->length_prefix_len) / 4; ++#if !defined(WORDS_BIGENDIAN) ++ goto no_unpacking_needed; ++#else ++ for (i = 0; i < count; i++) { ++ ((uint32_t *) array)[i] = parse_fixed_uint32(at); ++ at += 4; ++ } ++ break; ++#endif ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ count = (scanned_member->len - scanned_member->length_prefix_len) / 8; ++#if !defined(WORDS_BIGENDIAN) ++ goto no_unpacking_needed; ++#else ++ for (i = 0; i < count; i++) { ++ ((uint64_t *) array)[i] = parse_fixed_uint64(at); ++ at += 8; ++ } ++ break; ++#endif ++ case PROTOBUF_C_TYPE_INT32: ++ while (rem > 0) { ++ unsigned s = scan_varint(rem, at); ++ if (s == 0) { ++ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); ++ return FALSE; ++ } ++ ((int32_t *) array)[count++] = parse_int32(s, at); ++ at += s; ++ rem -= s; ++ } ++ break; ++ case PROTOBUF_C_TYPE_SINT32: ++ while (rem > 0) { ++ unsigned s = scan_varint(rem, at); ++ if (s == 0) { ++ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); ++ return FALSE; ++ } ++ ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); ++ at += s; ++ rem -= s; ++ } ++ break; ++ case PROTOBUF_C_TYPE_ENUM: ++ case PROTOBUF_C_TYPE_UINT32: ++ while (rem > 0) { ++ unsigned s = scan_varint(rem, at); ++ if (s == 0) { ++ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); ++ return FALSE; ++ } ++ ((uint32_t *) array)[count++] = parse_uint32(s, at); ++ at += s; ++ rem -= s; ++ } ++ break; ++ ++ case PROTOBUF_C_TYPE_SINT64: ++ while (rem > 0) { ++ unsigned s = scan_varint(rem, at); ++ if (s == 0) { ++ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); ++ return FALSE; ++ } ++ ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); ++ at += s; ++ rem -= s; ++ } ++ break; ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_UINT64: ++ while (rem > 0) { ++ unsigned s = scan_varint(rem, at); ++ if (s == 0) { ++ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); ++ return FALSE; ++ } ++ ((int64_t *) array)[count++] = parse_uint64(s, at); ++ at += s; ++ rem -= s; ++ } ++ break; ++ case PROTOBUF_C_TYPE_BOOL: ++ count = rem; ++ for (i = 0; i < count; i++) { ++ if (at[i] > 1) { ++ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); ++ return FALSE; ++ } ++ ((protobuf_c_boolean *) array)[i] = at[i]; ++ } ++ break; ++ default: ++ PROTOBUF_C__ASSERT_NOT_REACHED(); ++ } ++ *p_n += count; ++ return TRUE; ++ ++#if !defined(WORDS_BIGENDIAN) ++no_unpacking_needed: ++ memcpy(array, at, count * siz); ++ *p_n += count; ++ return TRUE; ++#endif ++} ++ ++static protobuf_c_boolean ++is_packable_type(ProtobufCType type) ++{ ++ return ++ type != PROTOBUF_C_TYPE_STRING && ++ type != PROTOBUF_C_TYPE_BYTES && ++ type != PROTOBUF_C_TYPE_MESSAGE; ++} ++ ++static protobuf_c_boolean ++parse_member(ScannedMember *scanned_member, ++ ProtobufCMessage *message, ++ ProtobufCAllocator *allocator) ++{ ++ const ProtobufCFieldDescriptor *field = scanned_member->field; ++ void *member; ++ ++ if (field == NULL) { ++ ProtobufCMessageUnknownField *ufield = ++ message->unknown_fields + ++ (message->n_unknown_fields++); ++ ufield->tag = scanned_member->tag; ++ ufield->wire_type = scanned_member->wire_type; ++ ufield->len = scanned_member->len; ++ ufield->data = do_alloc(allocator, scanned_member->len); ++ if (ufield->data == NULL) ++ return FALSE; ++ memcpy(ufield->data, scanned_member->data, ufield->len); ++ return TRUE; ++ } ++ member = (char *) message + field->offset; ++ switch (field->label) { ++ case PROTOBUF_C_LABEL_REQUIRED: ++ return parse_required_member(scanned_member, member, ++ allocator, TRUE); ++ case PROTOBUF_C_LABEL_OPTIONAL: ++ return parse_optional_member(scanned_member, member, ++ message, allocator); ++ case PROTOBUF_C_LABEL_REPEATED: ++ if (scanned_member->wire_type == ++ PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && ++ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || ++ is_packable_type(field->type))) ++ { ++ return parse_packed_repeated_member(scanned_member, ++ member, message); ++ } else { ++ return parse_repeated_member(scanned_member, ++ member, message, ++ allocator); ++ } ++ } ++ PROTOBUF_C__ASSERT_NOT_REACHED(); ++ return 0; ++} ++ ++/** ++ * 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). ++ */ ++static void ++message_init_generic(const ProtobufCMessageDescriptor *desc, ++ ProtobufCMessage *message) ++{ ++ unsigned i; ++ ++ memset(message, 0, desc->sizeof_message); ++ message->descriptor = desc; ++ for (i = 0; i < desc->n_fields; i++) { ++ if (desc->fields[i].default_value != NULL && ++ desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) ++ { ++ void *field = ++ STRUCT_MEMBER_P(message, desc->fields[i].offset); ++ const void *dv = desc->fields[i].default_value; ++ ++ switch (desc->fields[i].type) { ++ case PROTOBUF_C_TYPE_INT32: ++ case PROTOBUF_C_TYPE_SINT32: ++ case PROTOBUF_C_TYPE_SFIXED32: ++ case PROTOBUF_C_TYPE_UINT32: ++ case PROTOBUF_C_TYPE_FIXED32: ++ case PROTOBUF_C_TYPE_FLOAT: ++ case PROTOBUF_C_TYPE_ENUM: ++ memcpy(field, dv, 4); ++ break; ++ case PROTOBUF_C_TYPE_INT64: ++ case PROTOBUF_C_TYPE_SINT64: ++ case PROTOBUF_C_TYPE_SFIXED64: ++ case PROTOBUF_C_TYPE_UINT64: ++ case PROTOBUF_C_TYPE_FIXED64: ++ case PROTOBUF_C_TYPE_DOUBLE: ++ memcpy(field, dv, 8); ++ break; ++ case PROTOBUF_C_TYPE_BOOL: ++ memcpy(field, dv, sizeof(protobuf_c_boolean)); ++ break; ++ case PROTOBUF_C_TYPE_BYTES: ++ memcpy(field, dv, sizeof(ProtobufCBinaryData)); ++ break; ++ ++ case PROTOBUF_C_TYPE_STRING: ++ case PROTOBUF_C_TYPE_MESSAGE: ++ /* ++ * The next line essentially implements a cast ++ * from const, which is totally unavoidable. ++ */ ++ *(const void **) field = dv; ++ break; ++ } ++ } ++ } ++} ++ ++/**@}*/ ++ ++/* ++ * ScannedMember slabs (an unpacking implementation detail). Before doing real ++ * unpacking, we first scan through the elements to see how many there are (for ++ * repeated fields), and which field to use (for non-repeated fields given ++ * twice). ++ * ++ * In order to avoid allocations for small messages, we keep a stack-allocated ++ * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we ++ * fill that up, we allocate each slab twice as large as the previous one. ++ */ ++#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4 ++ ++/* ++ * The number of slabs, including the stack-allocated ones; choose the number so ++ * that we would overflow if we needed a slab larger than provided. ++ */ ++#define MAX_SCANNED_MEMBER_SLAB \ ++ (sizeof(unsigned int)*8 - 1 \ ++ - 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, ++ size_t len, const uint8_t *data) ++{ ++ ProtobufCMessage *rv; ++ size_t rem = len; ++ const uint8_t *at = data; ++ const ProtobufCFieldDescriptor *last_field = desc->fields + 0; ++ ScannedMember first_member_slab[1 << ++ FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; ++ ++ /* ++ * scanned_member_slabs[i] is an array of arrays of ScannedMember. ++ * The first slab (scanned_member_slabs[0] is just a pointer to ++ * first_member_slab), above. All subsequent slabs will be allocated ++ * using the allocator. ++ */ ++ ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; ++ unsigned which_slab = 0; /* the slab we are currently populating */ ++ unsigned in_slab_index = 0; /* number of members in the slab */ ++ size_t n_unknown = 0; ++ unsigned f; ++ unsigned j; ++ unsigned i_slab; ++ unsigned last_field_index = 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__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 ++ * provide the function, and (2) descriptors constructed from some other ++ * source (most likely, direct construction from the .proto file). ++ */ ++ if (desc->message_init != NULL) ++ protobuf_c_message_init(desc, rv); ++ else ++ message_init_generic(desc, rv); ++ ++ while (rem > 0) { ++ uint32_t tag; ++ ProtobufCWireType wire_type; ++ size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); ++ const ProtobufCFieldDescriptor *field; ++ ScannedMember tmp; ++ ++ if (used == 0) { ++ PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", ++ (unsigned) (at - data)); ++ goto error_cleanup_during_scan; ++ } ++ /* ++ * \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 = ++ int_range_lookup(desc->n_field_ranges, ++ desc->field_ranges, ++ tag); ++ if (field_index < 0) { ++ field = NULL; ++ n_unknown++; ++ } else { ++ field = desc->fields + field_index; ++ last_field = field; ++ last_field_index = field_index; ++ } ++ } else { ++ field = last_field; ++ } ++ ++ if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) ++ REQUIRED_FIELD_BITMAP_SET(last_field_index); ++ ++ at += used; ++ rem -= used; ++ tmp.tag = tag; ++ tmp.wire_type = wire_type; ++ tmp.field = field; ++ tmp.data = at; ++ tmp.length_prefix_len = 0; ++ ++ switch (wire_type) { ++ case PROTOBUF_C_WIRE_TYPE_VARINT: { ++ unsigned max_len = rem < 10 ? rem : 10; ++ unsigned i; ++ ++ for (i = 0; i < max_len; i++) ++ if ((at[i] & 0x80) == 0) ++ break; ++ if (i == max_len) { ++ PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", ++ (unsigned) (at - data)); ++ goto error_cleanup_during_scan; ++ } ++ tmp.len = i + 1; ++ break; ++ } ++ case PROTOBUF_C_WIRE_TYPE_64BIT: ++ if (rem < 8) { ++ PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", ++ (unsigned) (at - data)); ++ goto error_cleanup_during_scan; ++ } ++ tmp.len = 8; ++ break; ++ case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { ++ size_t pref_len; ++ ++ tmp.len = scan_length_prefixed_data(rem, at, &pref_len); ++ if (tmp.len == 0) { ++ /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ ++ goto error_cleanup_during_scan; ++ } ++ tmp.length_prefix_len = pref_len; ++ break; ++ } ++ case PROTOBUF_C_WIRE_TYPE_32BIT: ++ if (rem < 4) { ++ PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", ++ (unsigned) (at - data)); ++ goto error_cleanup_during_scan; ++ } ++ tmp.len = 4; ++ break; ++ default: ++ PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", ++ wire_type, (unsigned) (at - data)); ++ goto error_cleanup_during_scan; ++ } ++ ++ if (in_slab_index == (1U << ++ (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) ++ { ++ size_t size; ++ ++ in_slab_index = 0; ++ if (which_slab == MAX_SCANNED_MEMBER_SLAB) { ++ PROTOBUF_C_UNPACK_ERROR("too many fields"); ++ goto error_cleanup_during_scan; ++ } ++ which_slab++; ++ size = sizeof(ScannedMember) ++ << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); ++ scanned_member_slabs[which_slab] = do_alloc(allocator, size); ++ if (scanned_member_slabs[which_slab] == NULL) ++ goto error_cleanup_during_scan; ++ } ++ scanned_member_slabs[which_slab][in_slab_index++] = tmp; ++ ++ if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { ++ size_t *n = STRUCT_MEMBER_PTR(size_t, rv, ++ field->quantifier_offset); ++ if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && ++ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || ++ is_packable_type(field->type))) ++ { ++ size_t count; ++ if (!count_packed_elements(field->type, ++ tmp.len - ++ tmp.length_prefix_len, ++ tmp.data + ++ tmp.length_prefix_len, ++ &count)) ++ { ++ PROTOBUF_C_UNPACK_ERROR("counting packed elements"); ++ goto error_cleanup_during_scan; ++ } ++ *n += count; ++ } else { ++ *n += 1; ++ } ++ } ++ ++ at += tmp.len; ++ rem -= tmp.len; ++ } ++ ++ /* allocate space for repeated fields, also check that all required fields have been set */ ++ for (f = 0; f < desc->n_fields; f++) { ++ const ProtobufCFieldDescriptor *field = desc->fields + f; ++ if (field->label == PROTOBUF_C_LABEL_REPEATED) { ++ size_t siz = ++ sizeof_elt_in_repeated_array(field->type); ++ size_t *n_ptr = ++ STRUCT_MEMBER_PTR(size_t, rv, ++ field->quantifier_offset); ++ if (*n_ptr != 0) { ++ unsigned n = *n_ptr; ++ *n_ptr = 0; ++ assert(rv->descriptor != NULL); ++#define CLEAR_REMAINING_N_PTRS() \ ++ for(f++;f < desc->n_fields; f++) \ ++ { \ ++ field = desc->fields + f; \ ++ if (field->label == PROTOBUF_C_LABEL_REPEATED) \ ++ STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \ ++ } ++ void *a = do_alloc(allocator, siz * n); ++ if (!a) { ++ CLEAR_REMAINING_N_PTRS(); ++ goto error_cleanup; ++ } ++ STRUCT_MEMBER(void *, rv, field->offset) = a; ++ } ++ } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) { ++ if (field->default_value == NULL && ++ !REQUIRED_FIELD_BITMAP_IS_SET(f)) ++ { ++ CLEAR_REMAINING_N_PTRS(); ++ PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'", ++ desc->name, field->name); ++ goto error_cleanup; ++ } ++ } ++ } ++#undef CLEAR_REMAINING_N_PTRS ++ ++ /* allocate space for unknown fields */ ++ if (n_unknown) { ++ rv->unknown_fields = do_alloc(allocator, ++ n_unknown * sizeof(ProtobufCMessageUnknownField)); ++ if (rv->unknown_fields == NULL) ++ goto error_cleanup; ++ } ++ ++ /* do real parsing */ ++ for (i_slab = 0; i_slab <= which_slab; i_slab++) { ++ unsigned max = (i_slab == which_slab) ? ++ in_slab_index : (1U << (i_slab + 4)); ++ ScannedMember *slab = scanned_member_slabs[i_slab]; ++ unsigned j; ++ ++ for (j = 0; j < max; j++) { ++ if (!parse_member(slab + j, rv, allocator)) { ++ PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", ++ slab->field ? slab->field->name : "*unknown-field*", ++ desc->name); ++ goto error_cleanup; ++ } ++ } ++ } ++ ++ /* 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; ++} ++ ++void ++protobuf_c_message_free_unpacked(ProtobufCMessage *message, ++ ProtobufCAllocator *allocator) ++{ ++ const ProtobufCMessageDescriptor *desc = message->descriptor; ++ unsigned f; ++ ++ ASSERT_IS_MESSAGE(message); ++ if (allocator == NULL) ++ allocator = &protobuf_c__allocator; ++ message->descriptor = NULL; ++ for (f = 0; f < desc->n_fields; f++) { ++ if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { ++ size_t n = STRUCT_MEMBER(size_t, ++ message, ++ desc->fields[f].quantifier_offset); ++ void *arr = STRUCT_MEMBER(void *, ++ message, ++ desc->fields[f].offset); ++ ++ if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { ++ unsigned i; ++ for (i = 0; i < n; i++) ++ do_free(allocator, ((char **) arr)[i]); ++ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { ++ unsigned i; ++ for (i = 0; i < n; i++) ++ do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); ++ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { ++ unsigned i; ++ for (i = 0; i < n; i++) ++ protobuf_c_message_free_unpacked( ++ ((ProtobufCMessage **) arr)[i], ++ allocator ++ ); ++ } ++ if (arr != NULL) ++ do_free(allocator, arr); ++ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { ++ char *str = STRUCT_MEMBER(char *, message, ++ desc->fields[f].offset); ++ ++ if (str && str != desc->fields[f].default_value) ++ do_free(allocator, str); ++ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { ++ void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, ++ desc->fields[f].offset).data; ++ const ProtobufCBinaryData *default_bd; ++ ++ default_bd = desc->fields[f].default_value; ++ if (data != NULL && ++ (default_bd == NULL || ++ default_bd->data != data)) ++ { ++ do_free(allocator, data); ++ } ++ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { ++ ProtobufCMessage *sm; ++ ++ sm = STRUCT_MEMBER(ProtobufCMessage *, message, ++ desc->fields[f].offset); ++ if (sm && sm != desc->fields[f].default_value) ++ protobuf_c_message_free_unpacked(sm, allocator); ++ } ++ } ++ ++ for (f = 0; f < message->n_unknown_fields; f++) ++ do_free(allocator, message->unknown_fields[f].data); ++ if (message->unknown_fields != NULL) ++ do_free(allocator, message->unknown_fields); ++ ++ do_free(allocator, message); ++} ++ ++void ++protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, ++ void *message) ++{ ++ descriptor->message_init((ProtobufCMessage *) (message)); ++} ++ ++protobuf_c_boolean ++protobuf_c_message_check(const ProtobufCMessage *message) ++{ ++ if (!message || ++ !message->descriptor || ++ message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) ++ { ++ 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; ++ } ++ ++ 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; ++} ++ ++/* === services === */ ++ ++typedef void (*GenericHandler) (void *service, ++ const ProtobufCMessage *input, ++ ProtobufCClosure closure, ++ void *closure_data); ++void ++protobuf_c_service_invoke_internal(ProtobufCService *service, ++ unsigned method_index, ++ const ProtobufCMessage *input, ++ ProtobufCClosure closure, ++ void *closure_data) ++{ ++ GenericHandler *handlers; ++ 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 ++ * other memory corruption bugs can cause this assertion too.) ++ */ ++ assert(method_index < service->descriptor->n_methods); ++ ++ /* ++ * Get the array of virtual methods (which are enumerated by the ++ * generated code). ++ */ ++ handlers = (GenericHandler *) (service + 1); ++ ++ /* ++ * 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); ++} ++ ++void ++protobuf_c_service_generated_init(ProtobufCService *service, ++ const ProtobufCServiceDescriptor *descriptor, ++ ProtobufCServiceDestroy destroy) ++{ ++ ASSERT_IS_SERVICE_DESCRIPTOR(descriptor); ++ service->descriptor = descriptor; ++ service->destroy = destroy; ++ service->invoke = protobuf_c_service_invoke_internal; ++ memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler)); ++} ++ ++void protobuf_c_service_destroy(ProtobufCService *service) ++{ ++ service->destroy(service); ++} ++ ++/* --- querying the descriptors --- */ ++ ++const ProtobufCEnumValue * ++protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, ++ const char *name) ++{ ++ unsigned start = 0; ++ unsigned count = desc->n_value_names; ++ ++ while (count > 1) { ++ unsigned mid = start + count / 2; ++ int rv = strcmp(desc->values_by_name[mid].name, name); ++ if (rv == 0) ++ return desc->values + desc->values_by_name[mid].index; ++ else if (rv < 0) { ++ count = start + count - (mid + 1); ++ start = mid + 1; ++ } else ++ count = mid - start; ++ } ++ if (count == 0) ++ return NULL; ++ if (strcmp(desc->values_by_name[start].name, name) == 0) ++ return desc->values + desc->values_by_name[start].index; ++ return NULL; ++} ++ ++const ProtobufCEnumValue * ++protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, ++ int value) ++{ ++ int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); ++ if (rv < 0) ++ return NULL; ++ return desc->values + rv; ++} ++ ++const ProtobufCFieldDescriptor * ++protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, ++ const char *name) ++{ ++ unsigned start = 0; ++ unsigned count = desc->n_fields; ++ const ProtobufCFieldDescriptor *field; ++ ++ while (count > 1) { ++ unsigned mid = start + count / 2; ++ int rv; ++ field = desc->fields + desc->fields_sorted_by_name[mid]; ++ rv = strcmp(field->name, name); ++ if (rv == 0) ++ return field; ++ else if (rv < 0) { ++ count = start + count - (mid + 1); ++ start = mid + 1; ++ } else ++ count = mid - start; ++ } ++ if (count == 0) ++ return NULL; ++ field = desc->fields + desc->fields_sorted_by_name[start]; ++ if (strcmp(field->name, name) == 0) ++ return field; ++ return NULL; ++} ++ ++const ProtobufCFieldDescriptor * ++protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc, ++ unsigned value) ++{ ++ int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value); ++ if (rv < 0) ++ return NULL; ++ return desc->fields + rv; ++} ++ ++const ProtobufCMethodDescriptor * ++protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, ++ const char *name) ++{ ++ unsigned start = 0; ++ unsigned count = desc->n_methods; ++ ++ while (count > 1) { ++ unsigned mid = start + count / 2; ++ unsigned mid_index = desc->method_indices_by_name[mid]; ++ const char *mid_name = desc->methods[mid_index].name; ++ int rv = strcmp(mid_name, name); ++ ++ if (rv == 0) ++ return desc->methods + desc->method_indices_by_name[mid]; ++ if (rv < 0) { ++ count = start + count - (mid + 1); ++ start = mid + 1; ++ } else { ++ count = mid - start; ++ } ++ } ++ if (count == 0) ++ return NULL; ++ if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0) ++ return desc->methods + desc->method_indices_by_name[start]; ++ return NULL; ++} +diff --git a/src/protobuf/protobuf-c/protobuf-c.h b/src/protobuf/protobuf-c/protobuf-c.h +new file mode 100644 +index 0000000..593df2d +--- /dev/null ++++ b/src/protobuf/protobuf-c/protobuf-c.h +@@ -0,0 +1,1079 @@ ++/* ++ * 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 ++ * met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/*! \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 ++ ++#ifdef __cplusplus ++# define PROTOBUF_C__BEGIN_DECLS extern "C" { ++# define PROTOBUF_C__END_DECLS } ++#else ++# define PROTOBUF_C__BEGIN_DECLS ++# define PROTOBUF_C__END_DECLS ++#endif ++ ++PROTOBUF_C__BEGIN_DECLS ++ ++#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) ++# ifdef PROTOBUF_C_EXPORT ++# define PROTOBUF_C__API __declspec(dllexport) ++# else ++# define PROTOBUF_C__API __declspec(dllimport) ++# endif ++#else ++# define PROTOBUF_C__API ++#endif ++ ++#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 ++ ++#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, ++ ++ /** ++ * 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, /**< 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; ++ ++/** ++ * 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; ++ ++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; ++ ++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; ++}; ++ ++/** ++ * Structure for the protobuf `bytes` scalar type. ++ * ++ * 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. ++ */ ++struct ProtobufCBinaryData { ++ size_t len; /**< Number of bytes in the `data` field. */ ++ uint8_t *data; /**< Data bytes. */ ++}; ++ ++/** ++ * 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); ++}; ++ ++/** ++ * 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 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; ++}; ++ ++/** ++ * Describes an enumeration as a whole, with all of its values. ++ */ ++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; ++ ++ /** Number elements in `values`. */ ++ unsigned n_values; ++ /** Array of distinct values, sorted by numeric value. */ ++ const ProtobufCEnumValue *values; ++ ++ /** 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; ++ ++ /** 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; ++}; ++ ++/** ++ * Represents a single value of an enumeration. ++ */ ++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; ++}; ++ ++/** ++ * 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 requires that the values in the original array are ++ * sorted. ++ */ ++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 ++ * this simple. ++ */ ++}; ++ ++/** ++ * 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(). ++ */ ++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; ++}; ++ ++/** ++ * Describes a message. ++ */ ++struct ProtobufCMessageDescriptor { ++ /** 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; ++ ++ /** ++ * 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); ++ ++PROTOBUF_C__API ++void ++protobuf_c_service_invoke_internal( ++ ProtobufCService *service, ++ unsigned method_index, ++ const ProtobufCMessage *input, ++ ProtobufCClosure closure, ++ void *closure_data); ++ ++/**@}*/ ++ ++PROTOBUF_C__END_DECLS ++ ++#endif /* PROTOBUF_C_H */ +-- +2.0.0 + diff --git a/net/ocserv/patches/0001-worker-call-sigprocmask-prior-to-entering-main-loop.patch b/net/ocserv/patches/0001-worker-call-sigprocmask-prior-to-entering-main-loop.patch deleted file mode 100644 index 783aa2b1d..000000000 --- a/net/ocserv/patches/0001-worker-call-sigprocmask-prior-to-entering-main-loop.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 9be381859d7c9077ed652a82ec06ef01494d413d Mon Sep 17 00:00:00 2001 -From: Nikos Mavrogiannopoulos -Date: Fri, 8 Aug 2014 12:27:08 +0200 -Subject: [PATCH 01/10] worker: call sigprocmask() prior to entering main loop - ---- - src/worker-vpn.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/worker-vpn.c b/src/worker-vpn.c -index 1c30f14..55ab375 100644 ---- a/src/worker-vpn.c -+++ b/src/worker-vpn.c -@@ -1856,6 +1856,7 @@ static int connect_handler(worker_st * ws) - bandwidth_init(&ws->b_tx, ws->config->tx_per_sec); - - session_info_send(ws); -+ sigprocmask(SIG_BLOCK, &blockset, NULL); - - /* worker main loop */ - for (;;) { --- -2.0.0 - diff --git a/net/ocserv/patches/0002-worker-when-the-UDP-socket-is-updated-update-the-DTL.patch b/net/ocserv/patches/0002-worker-when-the-UDP-socket-is-updated-update-the-DTL.patch deleted file mode 100644 index 0c5ea02ce..000000000 --- a/net/ocserv/patches/0002-worker-when-the-UDP-socket-is-updated-update-the-DTL.patch +++ /dev/null @@ -1,26 +0,0 @@ -From c567a129f4dac88d1b3c4508484a2dffd78e1e5a Mon Sep 17 00:00:00 2001 -From: Nikos Mavrogiannopoulos -Date: Fri, 22 Aug 2014 11:57:15 +0200 -Subject: [PATCH 06/10] worker: when the UDP socket is updated, update the DTLS - session - ---- - src/worker-misc.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/worker-misc.c b/src/worker-misc.c -index 52be346..bde24d7 100644 ---- a/src/worker-misc.c -+++ b/src/worker-misc.c -@@ -139,6 +139,8 @@ int handle_worker_commands(struct worker_st *ws) - close(fd); - return 0; - } -+ if (ws->dtls_session != NULL) -+ gnutls_transport_set_ptr(ws->dtls_session, (gnutls_transport_ptr_t)(long)fd); - } else { /* received client hello */ - ws->udp_state = UP_SETUP; - } --- -2.0.0 - diff --git a/net/ocserv/patches/0003-after-fork-restore-the-default-signal-mask.patch b/net/ocserv/patches/0003-after-fork-restore-the-default-signal-mask.patch deleted file mode 100644 index c16228a4a..000000000 --- a/net/ocserv/patches/0003-after-fork-restore-the-default-signal-mask.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 817f757577ef78bcc19aecf73d6ecf1b11258c82 Mon Sep 17 00:00:00 2001 -From: Nikos Mavrogiannopoulos -Date: Fri, 22 Aug 2014 15:23:16 +0200 -Subject: [PATCH 07/10] after fork restore the default signal mask - ---- - src/main-user.c | 2 ++ - src/main.c | 5 +++-- - src/main.h | 1 + - 3 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/src/main-user.c b/src/main-user.c -index bc16e3a..9b57e00 100644 ---- a/src/main-user.c -+++ b/src/main-user.c -@@ -66,6 +66,8 @@ const char* script; - char local[64] = ""; - char remote[64] = ""; - -+ sigprocmask(SIG_SETMASK, &sig_default_set, NULL); -+ - snprintf(real, sizeof(real), "%u", (unsigned)proc->pid); - setenv("ID", real, 1); - -diff --git a/src/main.c b/src/main.c -index 8bb3061..a71bde6 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -64,6 +64,7 @@ static unsigned int terminate = 0; - static unsigned int reload_conf = 0; - unsigned int need_maintenance = 0; - static unsigned int need_children_cleanup = 0; -+sigset_t sig_default_set; - - static void ms_sleep(unsigned ms) - { -@@ -974,7 +975,7 @@ int main(int argc, char** argv) - exit(1); - } - -- sigprocmask(SIG_BLOCK, &blockset, NULL); -+ sigprocmask(SIG_BLOCK, &blockset, &sig_default_set); - alarm(MAINTAINANCE_TIME(s)); - - for (;;) { -@@ -1061,6 +1062,7 @@ int main(int argc, char** argv) - /* close any open descriptors, and erase - * sensitive data before running the worker - */ -+ sigprocmask(SIG_SETMASK, &sig_default_set, NULL); - close(cmd_fd[0]); - clear_lists(s); - -@@ -1096,7 +1098,6 @@ int main(int argc, char** argv) - * sensitive data have to be overwritten anyway. */ - malloc_trim(0); - #endif -- sigprocmask(SIG_UNBLOCK, &blockset, NULL); - vpn_server(ws); - exit(0); - } else if (pid == -1) { -diff --git a/src/main.h b/src/main.h -index de3d00c..cf5a0b1 100644 ---- a/src/main.h -+++ b/src/main.h -@@ -39,6 +39,7 @@ - - #define COOKIE_KEY_SIZE 16 - -+extern sigset_t sig_default_set; - int cmd_parser (void *pool, int argc, char **argv, struct cfg_st** config); - void reload_cfg_file(void *pool, struct cfg_st* config); - void clear_cfg_file(struct cfg_st* config); --- -2.0.0 - diff --git a/net/ocserv/patches/0004-added-work-around-for-infinite-loop-if-the-UDP-descr.patch b/net/ocserv/patches/0004-added-work-around-for-infinite-loop-if-the-UDP-descr.patch deleted file mode 100644 index 33f03c650..000000000 --- a/net/ocserv/patches/0004-added-work-around-for-infinite-loop-if-the-UDP-descr.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/src/worker-vpn.c b/src/worker-vpn.c -index 55ab375..12cd3c8 100644 ---- a/src/worker-vpn.c -+++ b/src/worker-vpn.c -@@ -1071,9 +1071,20 @@ static int dtls_mainloop(worker_st * ws, struct timespec *tnow) - { - int ret, l; - -+#if GNUTLS_VERSION_NUMBER <= 0x030210 -+ /* work-around an infinite loop caused by gnutls_record_recv() -+ * always succeeding by counting every error as a discarded packet. -+ */ -+ ret = gnutls_record_get_discarded(ws->dtls_session); -+ if (ret > 1000) { -+ ws->udp_state = UP_DISABLED; -+ return 0; -+ } -+#endif - switch (ws->udp_state) { - case UP_ACTIVE: - case UP_INACTIVE: -+ - ret = - tls_recv_nb(ws->dtls_session, ws->buffer, ws->buffer_size); - oclog(ws, LOG_TRANSFER_DEBUG,