blob: e562c09eb6e6e5117a003c20c63211b563f6771d [file] [log] [blame]
/*
* Copyright (C) 2003, 2004, 2005, 2014, 2015 Filip Pizlo. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 FILIP PIZLO ``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 FILIP PIZLO 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.
*/
#include "tsf_internal.h"
#include "tsf_format.h"
#include <unistd.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
#ifdef DEBUG_REFLECT_ALLOC
static int64_t reflect_balance = 0;
int64_t tsf_reflect_get_balance() {
return reflect_balance;
}
#define increment_reflect_balance() do {\
reflect_balance++;\
} while(0)
#define decrement_reflect_balance() do {\
reflect_balance--;\
} while(0)
#else
#define increment_reflect_balance() do {\
} while(0)
#define decrement_reflect_balance() do {\
} while(0)
#endif
#define is_struct_or_array(type) \
(type->kind_code == TSF_TK_STRUCT || \
type->kind_code == TSF_TK_ARRAY)
tsf_reflect_t *tsf_reflect_create(tsf_type_t *type) {
tsf_reflect_t *ret;
if (type == NULL) {
return NULL;
}
ret = malloc(sizeof(tsf_reflect_t));
if (ret == NULL) {
tsf_set_errno("Could not allocate tsf_reflect_t structure.");
return NULL;
}
ret->type = tsf_type_dup(type);
switch (type->kind_code) {
case TSF_TK_ARRAY:
ret->u.c.array = NULL;
ret->u.c.size = 0;
break;
case TSF_TK_STRUCT:
ret->u.c.size = tsf_struct_type_get_num_elements(type);
ret->u.c.array = malloc(sizeof(tsf_reflect_t*) *
ret->u.c.size);
if (ret->u.c.array == NULL) {
free(ret);
tsf_type_destroy(ret->type);
tsf_set_errno("Could not allocate array of pointers in "
"tsf_reflect_create()");
return NULL;
}
bzero(ret->u.c.array, sizeof(tsf_reflect_t*) * ret->u.c.size);
break;
case TSF_TK_CHOICE:
ret->u.h.choice = UINT32_MAX;
ret->u.h.data = NULL;
break;
case TSF_TK_INT8:
case TSF_TK_UINT8:
case TSF_TK_INT16:
case TSF_TK_UINT16:
case TSF_TK_INT32:
case TSF_TK_UINT32:
case TSF_TK_INT64:
case TSF_TK_UINT64:
case TSF_TK_INTEGER:
case TSF_TK_LONG:
case TSF_TK_FLOAT:
case TSF_TK_DOUBLE:
case TSF_TK_BIT:
case TSF_TK_VOID:
case TSF_TK_STRING:
case TSF_TK_ANY:
tsf_set_error(TSF_E_BAD_TYPE_KIND,
"To create tsf_reflect_t objects of type "
"%s, use tsf_reflect_create_%s()",
tsf_type_kind_tsf_name(type->kind_code),
tsf_type_kind_lc_name(type->kind_code));
tsf_type_destroy(ret->type);
free(ret);
ret = NULL;
break;
default:
tsf_type_destroy(ret->type);
tsf_set_error(TSF_E_BAD_TYPE_KIND,
"'" fui8 "' is not a valid kind type for "
"tsf_reflect_create()",
type->kind_code);
free(ret);
ret = NULL;
break;
}
increment_reflect_balance();
return ret;
}
#define DEFINE_REFLECT_CREATE_GET(type_lc_name, type_lc, type_uc) \
tsf_reflect_t *tsf_reflect_create_##type_lc_name(type_lc value) { \
tsf_reflect_t *ret; \
\
ret = malloc(sizeof(tsf_reflect_t)); \
if (ret == NULL) { \
tsf_set_errno("Could not allocate tsf_reflect_t structure."); \
return NULL; \
} \
\
ret->type = tsf_type_create(type_uc); \
ret->u.p_##type_lc_name = value; \
\
increment_reflect_balance(); \
\
return ret; \
} \
\
type_lc tsf_##type_lc_name##_reflect_get(tsf_reflect_t *data) { \
return data->u.p_##type_lc_name; \
}
DEFINE_REFLECT_CREATE_GET(int16_t, int16_t, TSF_TK_INT16)
DEFINE_REFLECT_CREATE_GET(uint16_t, uint16_t, TSF_TK_UINT16)
DEFINE_REFLECT_CREATE_GET(int32_t, int32_t, TSF_TK_INT32)
DEFINE_REFLECT_CREATE_GET(uint32_t, uint32_t, TSF_TK_UINT32)
DEFINE_REFLECT_CREATE_GET(int64_t, int64_t, TSF_TK_INT64)
DEFINE_REFLECT_CREATE_GET(uint64_t, uint64_t, TSF_TK_UINT64)
DEFINE_REFLECT_CREATE_GET(integer, int32_t, TSF_TK_INTEGER)
DEFINE_REFLECT_CREATE_GET(long, int64_t, TSF_TK_LONG)
DEFINE_REFLECT_CREATE_GET(float, float, TSF_TK_FLOAT)
DEFINE_REFLECT_CREATE_GET(double, double, TSF_TK_DOUBLE)
static tsf_reflect_t int8_data[256];
static tsf_reflect_t uint8_data[256];
static tsf_reflect_t bit_data_true,
bit_data_false;
static tsf_reflect_t void_data;
static void init_reflect(void) {
unsigned i;
for (i = 0; i < 256; ++i) {
int8_data[i].type = tsf_type_create(TSF_TK_INT8);
int8_data[i].u.p_int8_t = i - 128;
uint8_data[i].type = tsf_type_create(TSF_TK_UINT8);
uint8_data[i].u.p_uint8_t = i;
}
bit_data_true.type = tsf_type_create(TSF_TK_BIT);
bit_data_true.u.bit = tsf_true;
bit_data_false.type = tsf_type_create(TSF_TK_BIT);
bit_data_false.u.bit = tsf_false;
void_data.type = tsf_type_create(TSF_TK_VOID);
}
static tsf_once_t once_control = TSF_ONCE_INIT;
static void check_init_reflect(void) {
tsf_once(&once_control, init_reflect);
}
tsf_reflect_t *tsf_reflect_create_int8_t(int8_t value) {
check_init_reflect();
return int8_data + value + 128;
}
tsf_reflect_t *tsf_reflect_create_uint8_t(uint8_t value) {
check_init_reflect();
return uint8_data + value;
}
int8_t tsf_int8_t_reflect_get(tsf_reflect_t *data) {
return data->u.p_int8_t;
}
uint8_t tsf_uint8_t_reflect_get(tsf_reflect_t *data) {
return data->u.p_uint8_t;
}
tsf_reflect_t *tsf_reflect_create_bit(tsf_bool_t value) {
check_init_reflect();
return value ? &bit_data_true : &bit_data_false;
}
tsf_reflect_t *tsf_reflect_create_void(void) {
check_init_reflect();
return &void_data;
}
tsf_reflect_t *tsf_reflect_create_string(const char *str) {
tsf_reflect_t *ret = malloc(sizeof(tsf_reflect_t));
if (ret == NULL) {
tsf_set_errno("Could not malloc tsf_reflect_t");
return NULL;
}
ret->type = tsf_type_create(TSF_TK_STRING);
ret->u.str = strdup(str);
if (ret->u.str == NULL) {
free(ret);
tsf_set_errno("Could not strdup()");
return NULL;
}
increment_reflect_balance();
return ret;
}
tsf_reflect_t *tsf_reflect_create_any(tsf_buffer_t *buf) {
tsf_reflect_t *ret=malloc(sizeof(tsf_reflect_t));
if (ret==NULL) {
tsf_set_errno("Could not malloc tsf_reflect_t");
tsf_buffer_destroy(buf);
return NULL;
}
ret->type=tsf_type_create(TSF_TK_ANY);
ret->u.any=buf;
increment_reflect_balance();
return ret;
}
tsf_reflect_t *tsf_reflect_clone(tsf_reflect_t *data) {
uint32_t i;
tsf_reflect_t *ret;
switch (data->type->kind_code) {
case TSF_TK_UINT8:
case TSF_TK_INT8:
case TSF_TK_BIT:
case TSF_TK_VOID:
return data;
default:
break;
}
ret = malloc(sizeof(tsf_reflect_t));
if (ret == NULL) {
tsf_set_errno("Could not allocate tsf_reflect_t structure.");
return NULL;
}
ret->type = tsf_type_dup(data->type);
if (is_struct_or_array(data->type)) {
ret->u.c.size = data->u.c.size;
ret->u.c.array = malloc(sizeof(tsf_reflect_t*) * ret->u.c.size);
if (ret->u.c.array == NULL) {
tsf_set_errno("Could not allocate array of pointers in "
"tsf_reflect_clone()");
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
/* set the elements of the array to NULL so that destroy
* works. */
bzero(ret->u.c.array,
sizeof(tsf_reflect_t*) * ret->u.c.size);
for (i = 0; i < ret->u.c.size; ++i) {
if (data->u.c.array[i] == NULL) {
continue;
}
ret->u.c.array[i] = tsf_reflect_clone(data->u.c.array[i]);
if (ret->u.c.array[i] == NULL) {
tsf_type_destroy(ret->type);
tsf_reflect_destroy(ret);
return NULL;
}
}
} else if (data->type->kind_code == TSF_TK_CHOICE) {
ret->u.h.choice = data->u.h.choice;
ret->u.h.data = tsf_reflect_clone(data->u.h.data);
if (ret->u.h.data == NULL) {
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
} else if (data->type->kind_code == TSF_TK_STRING) {
ret->u.str = strdup(data->u.str);
if (ret->u.str == NULL) {
tsf_set_errno("Could not strdup()");
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
} else if (data->type->kind_code == TSF_TK_ANY) {
ret->u.any = tsf_buffer_dup(data->u.any);
if (ret->u.any == NULL) {
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
} else {
/* just copy the bits */
ret->u = data->u;
}
increment_reflect_balance();
return ret;
}
void tsf_reflect_destroy(tsf_reflect_t *data) {
uint32_t i;
switch (data->type->kind_code) {
case TSF_TK_UINT8:
case TSF_TK_INT8:
case TSF_TK_BIT:
case TSF_TK_VOID:
return;
default:
break;
}
decrement_reflect_balance();
if (is_struct_or_array(data->type)) {
for (i = 0; i < data->u.c.size; ++i) {
if (data->u.c.array[i] == NULL) {
continue;
}
tsf_reflect_destroy(data->u.c.array[i]);
}
if (data->u.c.array != NULL) {
free(data->u.c.array);
}
} else if (data->type->kind_code == TSF_TK_CHOICE) {
if (data->u.h.data != NULL) {
tsf_reflect_destroy(data->u.h.data);
}
} else if (data->type->kind_code == TSF_TK_STRING) {
free(data->u.str);
} else if (data->type->kind_code == TSF_TK_ANY) {
tsf_buffer_destroy(data->u.any);
}
tsf_type_destroy(data->type);
free(data);
}
tsf_bool_t tsf_reflect_verify(tsf_reflect_t *data) {
uint32_t i;
if (!is_struct_or_array(data->type)) {
return tsf_true;
}
for (i = 0; i < data->u.c.size; ++i) {
if (data->u.c.array[i] == NULL) {
tsf_set_error(TSF_E_ELEMENT_NULL,
"In %s at index = " fui32,
data->type->kind_code == TSF_TK_ARRAY ?
"an array" : "a struct",
i);
return tsf_false;
}
}
return tsf_true;
}
/* does a prepass for producing a buffer */
static uint32_t write_calc_size(tsf_reflect_t *data) {
uint32_t i, num_bits = 0, ret = 0;
switch (data->type->kind_code) {
case TSF_TK_INTEGER:
return size_of_tsf_integer(data->u.p_integer);
case TSF_TK_LONG:
return size_of_tsf_long(data->u.p_long);
default:
break;
}
if (tsf_type_kind_is_primitive(data->type->kind_code)) {
return tsf_primitive_type_kind_size_of(data->type->kind_code);
}
if (data->type->kind_code == TSF_TK_BIT) {
return 1;
}
if (data->type->kind_code == TSF_TK_VOID) {
return 0;
}
if (data->type->kind_code == TSF_TK_STRING) {
return strlen(data->u.str) + 1;
}
if (data->type->kind_code == TSF_TK_ANY) {
return tsf_buffer_calc_size(data->u.any);
}
if (data->type->kind_code == TSF_TK_CHOICE) {
if (tsf_choice_type_get_num_elements(data->type) >= 256) {
if (data->type->u.h.choice_as_full_word) {
ret += 4;
} else {
ret += size_of_tsf_unsigned(data->u.h.choice + 1);
}
} else {
ret += 1;
}
if (data->u.h.data != NULL) {
ret += write_calc_size(data->u.h.data);
}
return ret;
}
if (data->type->kind_code == TSF_TK_ARRAY) {
if (data->u.c.size >= 255) {
ret += 5;
} else {
ret += 1;
}
}
for (i = 0; i < data->u.c.size; ++i) {
if (data->u.c.array[i]->type->kind_code == TSF_TK_BIT) {
++num_bits;
} else {
ret += write_calc_size(data->u.c.array[i]);
}
}
ret += ((num_bits + 7) >> 3);
return ret;
}
static tsf_bool_t write_mainpass(tsf_reflect_t *data,
tsf_type_out_map_t *type_map,
uint8_t **buf) {
switch (data->type->kind_code) {
case TSF_TK_INT8:
case TSF_TK_UINT8:
case TSF_TK_BIT:
copy_htonc_incdst(*buf, &data->u.p_uint8_t);
break;
case TSF_TK_INT16:
case TSF_TK_UINT16:
copy_htons_incdst(*buf, (uint8_t*)&data->u.p_uint16_t);
break;
case TSF_TK_INT32:
case TSF_TK_UINT32:
copy_htonl_incdst(*buf, (uint8_t*)&data->u.p_uint32_t);
break;
case TSF_TK_INT64:
case TSF_TK_UINT64:
copy_htonll_incdst(*buf, (uint8_t*)&data->u.p_uint64_t);
break;
case TSF_TK_INTEGER:
*buf += write_tsf_integer(*buf, data->u.p_integer);
break;
case TSF_TK_LONG:
*buf += write_tsf_long(*buf, data->u.p_long);
break;
case TSF_TK_FLOAT:
copy_htonf_incdst(*buf, (uint8_t*)&data->u.p_float);
break;
case TSF_TK_DOUBLE:
copy_htond_incdst(*buf, (uint8_t*)&data->u.p_double);
break;
case TSF_TK_ARRAY: {
uint8_t tmp;
if (data->u.c.size >= 255) {
tmp = (uint8_t)255;
copy_htonc_incdst(*buf, &tmp);
copy_htonl_incdst(*buf, (uint8_t*)&data->u.c.size);
} else {
tmp = (uint8_t)data->u.c.size;
copy_htonc_incdst(*buf, &tmp);
}
if (tsf_type_get_kind_code(
tsf_array_type_get_element_type(data->type))
== TSF_TK_BIT) {
uint32_t i, j;
uint8_t value;
for (i = 0; i + 7 < data->u.c.size; i += 8) {
value = 0;
for (j = 0; j < 8; ++j) {
if (data->u.c.array[i + j]->u.bit) {
value |= (1 << j);
}
}
copy_htonc_incdst(*buf, &value);
}
if (data->u.c.size > i) {
value = 0;
for (j = 0; j < data->u.c.size - i; ++j) {
if (data->u.c.array[i + j]->u.bit) {
value |= (1 << j);
}
}
copy_htonc_incdst(*buf, &value);
}
} else {
uint32_t i;
for (i = 0; i < data->u.c.size; ++i) {
if (!write_mainpass(data->u.c.array[i],
type_map,
buf)) {
return tsf_false;
}
}
}
break;
}
case TSF_TK_STRUCT: {
uint32_t i;
uint8_t value, bit;
for (i = 0; i < data->u.c.size; ++i) {
if (data->u.c.array[i]->type->kind_code == TSF_TK_BIT) {
continue;
}
if (!write_mainpass(data->u.c.array[i],
type_map,
buf)) {
return tsf_false;
}
}
value = 0;
bit = 0;
for (i = 0; i < data->u.c.size; ++i) {
if (data->u.c.array[i]->type->kind_code != TSF_TK_BIT) {
continue;
}
if (data->u.c.array[i]->u.bit) {
value |= (1 << bit);
}
++bit;
if (bit == 8) {
copy_htonc_incdst(*buf, &value);
value = 0;
bit = 0;
}
}
if (bit) {
copy_htonc_incdst(*buf, &value);
}
break;
}
case TSF_TK_CHOICE:
if (tsf_choice_type_get_num_elements(data->type) >= 256) {
if (data->type->u.h.choice_as_full_word) {
copy_htonl_incdst(*buf, (uint8_t*)&data->u.h.choice);
} else {
*buf += write_tsf_unsigned(*buf, data->u.h.choice + 1);
}
} else {
uint8_t choice_8bit;
if (data->u.h.choice == UINT32_MAX) {
choice_8bit = 255;
} else {
choice_8bit = data->u.h.choice;
}
copy_htonc_incdst(*buf, &choice_8bit);
}
if (data->u.h.data != NULL) {
if (!write_mainpass(data->u.h.data,
type_map,
buf)) {
return tsf_false;
}
}
break;
case TSF_TK_VOID:
break;
case TSF_TK_STRING:
#ifdef HAVE_STPCPY
*buf = (uint8_t*)stpcpy((char*)*buf, data->u.str) + 1;
#else
strcpy((char*)*buf, data->u.str);
*buf += strlen(data->u.str) + 1;
#endif
break;
case TSF_TK_ANY:
if (!tsf_buffer_write_to_buf(data->u.any,
type_map,
buf)) {
return tsf_false;
}
break;
default:
tsf_set_error(TSF_E_BAD_TYPE_KIND,
fui8 " is not a recognized kind code.",
data->type->kind_code);
return tsf_false;
}
return tsf_true;
}
tsf_buffer_t *tsf_reflect_make_buffer(tsf_reflect_t *data) {
uint32_t size;
uint8_t *buf,*cur;
tsf_type_out_map_t *type_map;
tsf_type_in_map_t *types;
if (!tsf_reflect_verify(data)) {
return NULL;
}
size=write_calc_size(data);
buf=malloc(size);
cur=buf;
if (buf==NULL) {
tsf_set_errno("Could not allocate data for buffer in "
"tsf_reflect_make_buffer().");
return NULL;
}
if (tsf_type_is_dynamic(data->type)) {
type_map=tsf_type_out_map_create();
if (type_map==NULL) {
free(buf);
return NULL;
}
} else {
type_map=NULL;
}
if (!write_mainpass(data,type_map,&cur)) {
if (type_map!=NULL) {
tsf_type_out_map_destroy(type_map);
}
free(buf);
return NULL;
}
if (cur!=buf+size) {
tsf_set_error(TSF_E_INTERNAL,
"tsf_reflect_make_buffer() was expected to write "
fui32 " bytes, but " fsz " bytes were written instead.",
size,cur-buf);
if (type_map!=NULL) {
tsf_type_out_map_destroy(type_map);
}
free(buf);
return NULL;
}
if (type_map==NULL) {
types=tsf_type_in_map_get_empty_singleton();
} else {
types=tsf_type_in_map_from_type_out_map(type_map);
if (types==NULL) {
free(buf);
return NULL;
}
}
return tsf_buffer_create(data->type,types,buf,size,tsf_true);
}
tsf_reflect_t *read_mainpass(tsf_type_t *type,
tsf_type_in_map_t *types,
uint8_t **buf,
uint8_t *end) {
tsf_reflect_t *ret = NULL; /* make GCC happy */
uint8_t ui8_tmp;
int8_t i8_tmp;
/* must special-case singletons!! */
switch (type->kind_code) {
case TSF_TK_INT8:
copy_ntohc_incsrc_bc((uint8_t*)&i8_tmp, *buf,
end,singleton_bounds_error);
return int8_data + i8_tmp + 128;
case TSF_TK_UINT8:
copy_ntohc_incsrc_bc(&ui8_tmp, *buf, end, singleton_bounds_error);
return uint8_data + ui8_tmp;
case TSF_TK_BIT:
copy_ntohc_incsrc_bc(&ui8_tmp, *buf, end, singleton_bounds_error);
if (ui8_tmp != 0) {
return &bit_data_true;
}
return &bit_data_false;
case TSF_TK_VOID:
return &void_data;
default:
break;
}
ret=malloc(sizeof(tsf_reflect_t));
if (ret==NULL) {
tsf_set_errno("Could not allocate tsf_reflect_t");
return NULL;
}
ret->type=tsf_type_dup(type);
switch (type->kind_code) {
case TSF_TK_INT8:
case TSF_TK_UINT8:
tsf_abort("Should have been handled above.");
break;
case TSF_TK_INT16:
case TSF_TK_UINT16:
copy_ntohs_incsrc_bc((uint8_t*)&ret->u.p_uint16_t, *buf,
end, bounds_error);
break;
case TSF_TK_INT32:
case TSF_TK_UINT32:
copy_ntohl_incsrc_bc((uint8_t*)&ret->u.p_uint32_t, *buf,
end, bounds_error);
break;
case TSF_TK_INT64:
case TSF_TK_UINT64:
copy_ntohll_incsrc_bc((uint8_t*)&ret->u.p_uint64_t, *buf,
end, bounds_error);
break;
case TSF_TK_INTEGER:
read_tsf_integer_incsrc(&ret->u.p_integer, *buf, end, bounds_error);
break;
case TSF_TK_LONG:
read_tsf_long_incsrc(&ret->u.p_long, *buf, end, bounds_error);
break;
case TSF_TK_FLOAT:
copy_ntohf_incsrc_bc((uint8_t*)&ret->u.p_float, *buf,
end, bounds_error);
break;
case TSF_TK_DOUBLE:
copy_ntohd_incsrc_bc((uint8_t*)&ret->u.p_double, *buf,
end, bounds_error);
break;
case TSF_TK_BIT:
tsf_abort("Should have been handled above.");
break;
case TSF_TK_ARRAY: {
uint32_t i;
tsf_type_t *ele_type = tsf_array_type_get_element_type(type);
uint8_t tmp;
copy_ntohc_incsrc_bc(&tmp, *buf, end, bounds_error);
if (tmp == 255) {
copy_ntohl_incsrc_bc((uint8_t*)&ret->u.c.size, *buf,
end, bounds_error);
} else {
ret->u.c.size = tmp;
}
ret->u.c.array = malloc(sizeof(tsf_reflect_t*) *
ret->u.c.size);
if (ret->u.c.array == NULL) {
tsf_set_errno("Could not allocate arrray of pointers "
"in tsf_reflect_from_buffer_impl()");
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
if (tsf_type_get_kind_code(ele_type) == TSF_TK_BIT) {
uint32_t i,j,k;
uint8_t value;
for (i = 0; i + 7 < ret->u.c.size; i += 8) {
copy_ntohc_incsrc_bc(&value, *buf,
end, bits_bounds_error);
for (j = 0; j < 8; ++j) {
ret->u.c.array[i + j] =
tsf_reflect_create_bit((value & (1 << j)) != 0);
if (ret->u.c.array[i + j] == NULL) {
for (k = 0; k < i + j; ++k) {
tsf_reflect_destroy(ret->u.c.array[k]);
}
tsf_type_destroy(ret->type);
free(ret->u.c.array);
free(ret);
return NULL;
}
}
}
if (ret->u.c.size > i) {
copy_ntohc_incsrc_bc(&value, *buf,
end, bits_bounds_error);
for (j = 0; j < ret->u.c.size - i; ++j) {
ret->u.c.array[i + j] =
tsf_reflect_create_bit((value & (1 << j)) != 0);
if (ret->u.c.array[i + j] == NULL) {
for (k = 0; k < i + j; ++k) {
tsf_reflect_destroy(ret->u.c.array[k]);
}
tsf_type_destroy(ret->type);
free(ret->u.c.array);
free(ret);
return NULL;
}
}
}
break;
bits_bounds_error:
for (j = 0; j < i; ++j) {
tsf_reflect_destroy(ret->u.c.array[j]);
}
free(ret->u.c.array);
goto bounds_error;
}
for (i = 0; i < ret->u.c.size; ++i) {
ret->u.c.array[i] = read_mainpass(ele_type, types, buf, end);
if (ret->u.c.array[i] == NULL) {
uint32_t j;
for (j = 0; j < i; ++j) {
tsf_reflect_destroy(ret->u.c.array[j]);
}
free(ret->u.c.array);
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
}
break;
}
case TSF_TK_STRUCT: {
uint32_t i;
uint8_t bit;
uint8_t value = 0; /* assignment only to make gcc happy */
tsf_named_type_t *n;
ret->u.c.size = tsf_struct_type_get_num_elements(type);
ret->u.c.array = malloc(sizeof(tsf_reflect_t*) *
tsf_struct_type_get_num_elements(type));
if (ret->u.c.array == NULL) {
tsf_set_errno("Could not allocate arrray of pointers "
"in tsf_reflect_from_buffer_impl()");
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
for (i = 0; i < tsf_struct_type_get_num_elements(type); ++i) {
n = tsf_struct_type_get_element(type, i);
if (n->type->kind_code == TSF_TK_BIT) {
continue;
}
ret->u.c.array[i] = read_mainpass(n->type, types, buf, end);
if (ret->u.c.array[i] == NULL) {
uint32_t j;
for (j = 0; j < i; ++j) {
n = tsf_struct_type_get_element(type,j);
if (n->type->kind_code == TSF_TK_BIT) {
continue;
}
tsf_reflect_destroy(ret->u.c.array[j]);
}
free(ret->u.c.array);
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
}
bit = 8;
for (i = 0; i < tsf_struct_type_get_num_elements(type); ++i) {
n = tsf_struct_type_get_element(type, i);
if (n->type->kind_code != TSF_TK_BIT) {
continue;
}
if (bit == 8) {
copy_ntohc_incsrc_bc(&value, *buf, end, bounds_error);
bit = 0;
}
ret->u.c.array[i] =
tsf_reflect_create_bit((value & (1 << bit)));
if (ret->u.c.array[i] == NULL) {
uint32_t j;
for (j = 0; j < i; ++j) {
tsf_reflect_destroy(ret->u.c.array[i]);
}
free(ret->u.c.array);
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
++bit;
}
break;
}
case TSF_TK_CHOICE:
if (tsf_choice_type_get_num_elements(type) >= 256) {
if (type->u.h.choice_as_full_word) {
copy_htonl_incsrc_bc((uint8_t*)&ret->u.h.choice, *buf,
end, bounds_error);
} else {
tsf_unsigned_t choice_value;
read_tsf_unsigned_incsrc(&choice_value, *buf,
end, bounds_error);
ret->u.h.choice = choice_value - 1;
}
} else {
uint8_t choice_8bit;
copy_htonc_incsrc_bc(&choice_8bit, *buf,
end, bounds_error);
ret->u.h.choice =
choice_8bit == 255 ? UINT32_MAX : choice_8bit;
}
if (ret->u.h.choice != UINT32_MAX) {
if (ret->u.h.choice >= tsf_choice_type_get_num_elements(type)) {
tsf_set_error(TSF_E_PARSE_ERROR,
"Choice is out of bounds of what we know: "
"the value we see is " fui32 " but the "
"number of elements in the choice type is "
fui32,
ret->u.h.choice,
tsf_choice_type_get_num_elements(type));
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
ret->u.h.data = read_mainpass(
tsf_choice_type_get_element(type, ret->u.h.choice)->type,
types, buf, end);
if (ret->u.h.data == NULL) {
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
} else {
ret->u.h.data = NULL;
}
break;
case TSF_TK_VOID:
tsf_abort("Should have been handled above.");
break;
case TSF_TK_STRING:
{
const size_t step = 128;
size_t size = step;
uint32_t i = 0;
ret->u.str = malloc(size);
for (;;) {
uint32_t n;
if (ret->u.str == NULL) {
tsf_set_errno("Could not (m|re)alloc string");
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
for (n = step; n-->0;) {
uint8_t c;
copy_ntohc_incsrc_bc(&c, *buf, end, bounds_error);
ret->u.str[i++] = c;
if (c == 0) {
return ret;
}
}
size += step;
ret->u.str = realloc(ret->u.str, size);
}
tsf_assert(!"unreachable");
break;
}
case TSF_TK_ANY: {
ret->u.any = tsf_buffer_read_from_buf(types,
buf,
end,
NULL);
if (ret->u.any == NULL) {
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
break;
}
default:
tsf_set_error(TSF_E_INTERNAL,
fui32 " is not a recognized kind code.",
type->kind_code);
tsf_type_destroy(ret->type);
free(ret);
return NULL;
}
increment_reflect_balance();
return ret;
bounds_error:
tsf_type_destroy(ret->type);
free(ret);
singleton_bounds_error:
tsf_set_error(TSF_E_PARSE_ERROR,
"Bounds error in reflecting parser");
return NULL;
}
tsf_reflect_t *tsf_reflect_from_buffer(tsf_buffer_t *buf) {
uint8_t *data;
tsf_reflect_t *ret;
check_init_reflect();
data=buf->data;
ret=read_mainpass(buf->type,
buf->types,
&data,
((uint8_t*)buf->data)+buf->size);
if (ret==NULL) {
return NULL;
}
if (data!=((uint8_t*)buf->data)+buf->size) {
tsf_set_error(TSF_E_PARSE_ERROR,
"tsf_reflect_from_buffer_impl() was expected to read "
fui32 " bytes, but " fsz " bytes were read instead.",
buf->size,((uint8_t*)data)-((uint8_t*)buf->data));
tsf_reflect_destroy(ret);
return NULL;
}
return ret;
}
tsf_type_t *tsf_reflect_get_type(tsf_reflect_t *data) {
return data->type;
}
tsf_type_kind_t tsf_reflect_get_kind_code(tsf_reflect_t *data) {
return tsf_type_get_kind_code(tsf_reflect_get_type(data));
}
static tsf_bool_t struct_set_element_impl(tsf_named_type_t *n,
tsf_reflect_t *data,
tsf_reflect_t *ele_data) {
uint32_t index;
if (!tsf_type_compare(n->type,ele_data->type)) {
tsf_set_error(TSF_E_BAD_TYPE,
"Third argument to tsf_struct_set_element() does "
"not have the right type.");
tsf_reflect_destroy(ele_data);
return tsf_false;
}
index=tsf_named_type_get_index(n);
if (data->u.c.array[index]!=NULL) {
tsf_reflect_destroy(data->u.c.array[index]);
}
data->u.c.array[index]=ele_data;
return tsf_true;
}
tsf_bool_t tsf_struct_reflect_set_element(tsf_reflect_t *data,
const char *name,
tsf_reflect_t *ele_data) {
tsf_named_type_t *n;
if (ele_data==NULL) {
return tsf_false;
}
if (data->type->kind_code!=TSF_TK_STRUCT) {
tsf_set_error(TSF_E_BAD_TYPE,
"First argument to tsf_struct_reflect_set_element() is "
"not a struct.");
tsf_reflect_destroy(ele_data);
return tsf_false;
}
n=tsf_struct_type_find_node(data->type,name);
if (n==NULL) {
tsf_reflect_destroy(ele_data);
return tsf_false;
}
return struct_set_element_impl(n,data,ele_data);
}
tsf_bool_t tsf_struct_reflect_set_element_by_index(tsf_reflect_t *data,
uint32_t index,
tsf_reflect_t *ele_data) {
if (ele_data==NULL) {
return tsf_false;
}
if (data->type->kind_code!=TSF_TK_STRUCT) {
tsf_set_error(TSF_E_BAD_TYPE,
"First argument to "
"tsf_struct_reflect_set_element_by_index() is not a "
"struct.");
tsf_reflect_destroy(ele_data);
return tsf_false;
}
if (index>=tsf_struct_type_get_num_elements(data->type)) {
tsf_set_error(TSF_E_INVALID_ARG,
"Index " fui32 " is out of bounds of valid element "
"indices (upper bound is " fui32 ") in "
"tsf_struct_reflect_set_element_by_index()",
index,
tsf_struct_type_get_num_elements(data->type));
return tsf_false;
}
return struct_set_element_impl(tsf_struct_type_get_element(data->type,
index),
data,
ele_data);
}
tsf_reflect_t *tsf_struct_reflect_get_element(tsf_reflect_t *data,
const char *name) {
tsf_named_type_t *n;
if (data->type->kind_code!=TSF_TK_STRUCT) {
tsf_set_error(TSF_E_BAD_TYPE,
"First argument to tsf_struct_reflect_get_element() is "
"not a struct.");
return tsf_false;
}
n=tsf_struct_type_find_node(data->type,name);
if (n==NULL) {
return NULL;
}
return data->u.c.array[tsf_named_type_get_index(n)];
}
tsf_reflect_t *tsf_struct_reflect_get_element_by_index(tsf_reflect_t *data,
uint32_t index) {
if (data->type->kind_code!=TSF_TK_STRUCT) {
tsf_set_error(TSF_E_BAD_TYPE,
"First argument to tsf_struct_reflect_get_element() is "
"not a struct.");
return tsf_false;
}
if (index>=tsf_struct_type_get_num_elements(data->type)) {
tsf_set_error(TSF_E_INVALID_ARG,
"Index " fui32 " is out of bounds of valid element "
"indices (upper bound is " fui32 ") in "
"tsf_struct_reflect_get_element_by_index()",
index,
tsf_struct_type_get_num_elements(data->type));
return tsf_false;
}
return data->u.c.array[index];
}
uint32_t tsf_struct_eflect_get_num_elements(tsf_reflect_t *data) {
return tsf_struct_type_get_num_elements(tsf_reflect_get_type(data));
}
tsf_bool_t tsf_array_reflect_append(tsf_reflect_t *data,
tsf_reflect_t *ele_data) {
if (ele_data==NULL) {
return tsf_false;
}
if (data->type->kind_code!=TSF_TK_ARRAY) {
tsf_set_error(TSF_E_BAD_TYPE,
"First argument to tsf_array_reflect_append() is "
"not an array.");
return tsf_false;
}
if (!tsf_type_compare(ele_data->type,
tsf_array_type_get_element_type(data->type))) {
tsf_set_error(TSF_E_BAD_TYPE,
"Second argument to tsf_array_reflect_append() does "
"match the element type of the array.");
return tsf_false;
}
if (data->u.c.array==NULL) {
data->u.c.array=malloc(sizeof(tsf_reflect_t*));
if (data->u.c.array==NULL) {
tsf_set_errno("Could not allocate array of tsf_reflect_t*");
return tsf_false;
}
} else {
tsf_reflect_t **new_array=realloc(data->u.c.array,
sizeof(tsf_reflect_t*)*
(data->u.c.size+1));
if (new_array==NULL) {
tsf_set_errno("Could not allocate array of tsf_reflect_t*");
return tsf_false;
}
data->u.c.array=new_array;
}
data->u.c.array[data->u.c.size++]=ele_data;
return tsf_true;
}
static tsf_bool_t choice_set_impl(tsf_named_type_t *n,
tsf_reflect_t *data,
tsf_reflect_t *ele_data) {
if (!tsf_type_compare(n->type,ele_data->type)) {
tsf_set_error(TSF_E_BAD_TYPE,
"Third argument to tsf_choice_reflect_set() does "
"not have the correct type.");
tsf_reflect_destroy(ele_data);
return tsf_false;
}
if (data->u.h.data!=NULL) {
tsf_reflect_destroy(data->u.h.data);
}
data->u.h.choice=n->index;
data->u.h.data=ele_data;
return tsf_true;
}
tsf_bool_t tsf_choice_reflect_set(tsf_reflect_t *data,
const char *choice,
tsf_reflect_t *ele_data) {
tsf_named_type_t *n;
if (choice==NULL) {
return tsf_choice_reflect_set_unknown(data);
}
if (ele_data==NULL) {
return tsf_false;
}
n=tsf_choice_type_find_node(data->type,choice);
if (n==NULL) {
tsf_reflect_destroy(ele_data);
return tsf_false;
}
return choice_set_impl(n,data,ele_data);
}
tsf_bool_t tsf_choice_reflect_set_by_index(tsf_reflect_t *data,
uint32_t index,
tsf_reflect_t *ele_data) {
if (index==UINT32_MAX) {
return tsf_choice_reflect_set_unknown(data);
}
if (ele_data==NULL) {
return tsf_false;
}
if (index>=tsf_choice_type_get_num_elements(data->type)) {
tsf_set_error(TSF_E_INVALID_ARG,
"Index " fui32 " is out of bounds of valid element "
"indices (upper bound is " fui32 ") in "
"tsf_choice_reflect_set_by_index()",
index,
tsf_struct_type_get_num_elements(data->type));
return tsf_false;
}
return choice_set_impl(tsf_choice_type_get_element(data->type,
index),
data,
ele_data);
}
tsf_bool_t tsf_choice_reflect_set_unknown(tsf_reflect_t *data) {
if (data->u.h.data!=NULL) {
tsf_reflect_destroy(data->u.h.data);
}
data->u.h.choice=UINT32_MAX;
data->u.h.data=NULL;
return tsf_true;
}
uint32_t tsf_choice_reflect_get_index(tsf_reflect_t *data) {
return data->u.h.choice;
}
tsf_bool_t tsf_choice_reflect_is_known(tsf_reflect_t *data) {
return tsf_choice_reflect_get_index(data) != TSF_UINT32_MAX;
}
const char *tsf_choice_reflect_get_choice(tsf_reflect_t *data) {
return tsf_choice_reflect_is_known(data) ?
tsf_choice_type_get_element(data->type,
data->u.h.choice)->name :
NULL;
}
tsf_reflect_t *tsf_choice_reflect_get_data(tsf_reflect_t *data) {
return data->u.h.data;
}
tsf_reflect_t *tsf_array_reflect_get_element(tsf_reflect_t *data,
uint32_t index) {
return data->u.c.array[index];
}
uint32_t tsf_array_reflect_get_num_elements(tsf_reflect_t *data) {
return data->u.c.size;
}
tsf_bool_t tsf_bit_reflect_get(tsf_reflect_t *data) {
return data->u.bit;
}
const char* tsf_string_reflect_get(tsf_reflect_t *data) {
return data->u.str;
}
tsf_buffer_t *tsf_any_reflect_get_buffer(tsf_reflect_t *data) {
return data->u.any;
}