Commit 75454052 authored by Lubomir Bulej's avatar Lubomir Bulej

Add C implementation Google protocol buffers by Dave Benson, version 1.2.1.

parent f47ae5d1
/*
* Copyright (c) 2008-2015, 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 <stdlib.h> /* for malloc, free */
#include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */
#include "protobuf-c.h"
#define TRUE 1
#define FALSE 0
#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0)
/* Workaround for Microsoft compilers. */
#ifdef _MSC_VER
# define inline __inline
#endif
/**
* \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
const char protobuf_c_empty_string[] = "";
/**
* 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(uint32_t number)
{
if (number < (1UL << 4)) {
return 1;
} else if (number < (1UL << 11)) {
return 2;
} else if (number < (1UL << 18)) {
return 3;
} else if (number < (1UL << 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 < (1UL << 7)) {
return 1;
} else if (v < (1UL << 14)) {
return 2;
} else if (v < (1UL << 21)) {
return 3;
} else if (v < (1UL << 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 < (1L << 7)) {
return 1;
} else if (v < (1L << 14)) {
return 2;
} else if (v < (1L << 21)) {
return 3;
} else if (v < (1L << 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 (uint32_t)(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 < (1UL << 3)) {
return 5;
} else if (upper_v < (1UL << 10)) {
return 6;
} else if (upper_v < (1UL << 17)) {
return 7;
} else if (upper_v < (1UL << 24)) {
return 8;
} else if (upper_v < (1UL << 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 (uint64_t)(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_ENUM:
case PROTOBUF_C_TYPE_INT32:
return rv + int32_size(*(const int32_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_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 oneof message field, including
* the space needed by the preceding tag. Returns 0 if the oneof field isn't
* selected or is not set.
*
* \param field
* Field descriptor for member.
* \param oneof_case
* Enum value that selects the field in the oneof.
* \param member
* Field to encode.
* \return
* Number of bytes required.
*/
static size_t
oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field,
uint32_t oneof_case,
const void *member)
{
if (oneof_case != field->id) {
return 0;
}
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;
}
return required_field_get_packed_size(field, member);
}
/**
* 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);
}
static protobuf_c_boolean
field_is_zeroish(const ProtobufCFieldDescriptor *field,
const void *member)
{
protobuf_c_boolean ret = FALSE;
switch (field->type) {
case PROTOBUF_C_TYPE_BOOL:
ret = (0 == *(const protobuf_c_boolean *) member);
break;
case PROTOBUF_C_TYPE_ENUM:
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:
ret = (0 == *(const uint32_t *) member);
break;
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:
ret = (0 == *(const uint64_t *) member);
break;
case PROTOBUF_C_TYPE_FLOAT:
ret = (0 == *(const float *) member);
break;
case PROTOBUF_C_TYPE_DOUBLE:
ret = (0 == *(const double *) member);
break;
case PROTOBUF_C_TYPE_STRING:
ret = (NULL == *(const char * const *) member) ||
('\0' == **(const char * const *) member);
break;
case PROTOBUF_C_TYPE_BYTES:
case PROTOBUF_C_TYPE_MESSAGE:
ret = (NULL == *(const void * const *) member);
break;
default:
ret = TRUE;
break;
}
return ret;
}
/**
* Calculate the serialized size of a single unlabeled message field, including
* the space needed by the preceding tag. Returns 0 if the field isn't set or
* if it is set to a "zeroish" value (null pointer or 0 for numerical values).
* Unlabeled fields are supported only in proto3.
*
* \param field
* Field descriptor for member.
* \param member
* Field to encode.
* \return
* Number of bytes required.
*/
static size_t
unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field,
const void *member)
{
if (field_is_zeroish(field, member))
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_ENUM:
case PROTOBUF_C_TYPE_INT32:
for (i = 0; i < count; i++)
rv += int32_size(((int32_t