/* * 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 #include #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_PTHREAD #include #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; }