/* * Copyright (C) 2003, 2004, 2005, 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 tsf_type_table_t *tsf_type_table_create() { tsf_type_table_t *ret = malloc(sizeof(tsf_type_table_t)); if (ret == NULL) { tsf_set_errno("Could not malloc tsf_type_table_t"); return NULL; } ret->elements = NULL; ret->num_elements = 0; ret->ele_table = tsf_st_init_strtable(); if (ret->ele_table == NULL) { tsf_set_errno("Could not tsf_st_init_strtable()"); free(ret); return NULL; } return ret; } tsf_bool_t tsf_type_table_copy(tsf_type_table_t *dest, tsf_type_table_t *src) { uint32_t i; for (i = 0; i < tsf_type_table_get_num_elements(src); ++i) { tsf_named_type_t *n = tsf_type_table_find_by_index(src, i), *n2; tsf_type_t *new_type = tsf_type_dup(n->type); if (new_type == NULL) { return tsf_false; } if (!tsf_type_table_append(dest, n->name, new_type)) { return tsf_false; } /* copy the optional attribute, offset info manually */ n2 = tsf_type_table_find_by_index(dest, tsf_type_table_get_num_elements(dest) - 1); n2->optional = n->optional; if (n->has_offset) { n2->has_offset = tsf_true; n2->offset = n->offset; } /* copy the comment manually */ if (n->comment != NULL) { n2->comment = strdup(n->comment); if (n2->comment == NULL) { tsf_set_errno("Could not allocate comment"); return tsf_false; } } } return tsf_true; } void tsf_type_table_destroy(tsf_type_table_t *tt) { uint32_t i; for (i = 0; i < tt->num_elements; ++i) { tsf_named_type_destroy(tt->elements[i]); } if (tt->elements != NULL) { free(tt->elements); } tsf_st_free_table(tt->ele_table); free(tt); } tsf_type_table_t *tsf_type_table_read(const char *name, tsf_reader_t reader, void *arg, tsf_limits_t *limits, uint32_t size_limit, uint32_t depth) { tsf_type_table_t *ret = tsf_type_table_create(); uint32_t i, num; if (ret == NULL) { return NULL; } if (!reader(arg, &num, sizeof(num))) { tsf_type_table_destroy(ret); return NULL; } num = ntohl(num); if (num > size_limit) { tsf_set_error(TSF_E_PARSE_ERROR, "%s size exceeds limit while parsing", name); tsf_type_table_destroy(ret); return NULL; } for (i = 0; i < num; ++i) { uint8_t ui8_tmp; char *str; /* parse the string */ str = tsf_read_string(reader, arg, TSF_STR_SIZE); if (str == NULL) { tsf_type_table_destroy(ret); return NULL; } /* now do other things */ if (!tsf_type_table_append(ret, str, tsf_type_read_rec(reader, arg, limits, depth))) { tsf_type_table_destroy(ret); free(str); return NULL; } free(str); if (!reader(arg, &ui8_tmp, 1)) { tsf_type_table_destroy(ret); return NULL; } if (ui8_tmp & ~3) { tsf_set_error(TSF_E_PARSE_ERROR, "Flags field contains bits I don't recognize: " fui8, ui8_tmp); tsf_type_table_destroy(ret); return NULL; } ret->elements[ret->num_elements - 1]->optional = (ui8_tmp & 2 ? tsf_true : tsf_false); if (ui8_tmp & 1) { /* parse a comment string. it can be arbitrarily long, so this parsing code is somewhat of a pain in the ass to write. */ if (!tsf_limits_allow_comments(limits)) { tsf_set_error(TSF_E_PARSE_ERROR, "Encountered a commented type while parsing, " "but comments are not allowed"); tsf_type_table_destroy(ret); return NULL; } str = tsf_read_string(reader, arg, TSF_MAX_COMMENT_SIZE); if (str == NULL) { tsf_type_table_destroy(ret); return NULL; } ret->elements[ret->num_elements - 1]->comment = str; } } return ret; } tsf_bool_t tsf_type_table_write(tsf_type_table_t *tt, tsf_writer_t writer, void *arg) { uint32_t ui32_tmp = htonl(tt->num_elements); uint8_t ui8_tmp; uint32_t i; if (!writer(arg, &ui32_tmp, sizeof(ui32_tmp))) { return tsf_false; } for (i = 0; i < tt->num_elements; ++i) { tsf_named_type_t *n = tt->elements[i]; if (!tsf_write_string(writer, arg, tsf_named_type_get_name(n))) { return tsf_false; } if (!tsf_type_write(tsf_named_type_get_type(n), writer, arg)) { return tsf_false; } ui8_tmp = 0; if (n->comment != NULL) { ui8_tmp |= 1; } if (n->optional) { ui8_tmp |= 2; } if (!writer(arg, &ui8_tmp, 1)) { return tsf_false; } if (n->comment != NULL) { if (!tsf_write_string(writer, arg, n->comment)) { return tsf_false; } } } return tsf_true; } int tsf_type_table_get_hash(tsf_type_table_t *tt) { int ret = 0; uint32_t i; for (i = 0; i < tt->num_elements; ++i) { ret += tsf_named_type_get_hash(tt->elements[i]); } return ret; } tsf_bool_t tsf_type_table_contains_dynamic(tsf_type_table_t *tt) { uint32_t i; for (i = 0; i < tt->num_elements; ++i) { if (tsf_type_is_dynamic(tt->elements[i]->type)) { return tsf_true; } } return tsf_false; } tsf_bool_t tsf_type_table_compare(tsf_type_table_t *a, tsf_type_table_t *b) { uint32_t i; if (a->num_elements != b->num_elements) { return tsf_false; } for (i = 0; i < a->num_elements; ++i) { if (strcmp(a->elements[i]->name, b->elements[i]->name)) { return tsf_false; } if (a->elements[i]->optional != b->elements[i]->optional) { return tsf_false; } if (!tsf_type_compare(a->elements[i]->type, b->elements[i]->type)) { return tsf_false; } } return tsf_true; } tsf_bool_t tsf_type_table_append(tsf_type_table_t *tt, const char *name, tsf_type_t *ele_type) { tsf_named_type_t *n; if (ele_type == NULL) { return tsf_false; } if (tsf_st_lookup(tt->ele_table, (char*)name, NULL)) { tsf_set_error(TSF_E_NAME_COLLISION, "Name '%s' is already used by another element", name); tsf_type_destroy(ele_type); return tsf_false; } if (tt->elements == NULL) { tt->elements = malloc(sizeof(tsf_named_type_t*)); if (tt->elements == NULL) { tsf_set_errno("Could not malloc tsf_named_type_t*"); tsf_type_destroy(ele_type); return tsf_false; } } else { tsf_named_type_t **new_array = realloc(tt->elements, sizeof(tsf_named_type_t*) * (tt->num_elements + 1)); if (new_array==NULL) { tsf_set_errno("Could not really array of tsf_named_type_t*"); tsf_type_destroy(ele_type); return tsf_false; } tt->elements = new_array; } n = tsf_named_type_create(name, ele_type, tt->num_elements); if (n == NULL) { return tsf_false; } if (tsf_st_insert(tt->ele_table, n->name, n) < 0) { tsf_set_errno("Failed to tsf_st_insert()"); tsf_type_destroy(ele_type); free(n); return tsf_false; } tt->elements[tt->num_elements++] = n; return tsf_true; } tsf_bool_t tsf_type_table_remove(tsf_type_table_t *tt, const char *name) { char *to_delete; void *old_value; tsf_named_type_t *n; to_delete = (char*)name; old_value = NULL; tsf_st_delete(tt->ele_table, &to_delete, &old_value); if (old_value == NULL) { tsf_set_error(TSF_E_ELE_NOT_FOUND, "Could not find \'%s\'", name); return tsf_false; } n = (tsf_named_type_t*)old_value; tt->elements[n->index] = tt->elements[--tt->num_elements]; tsf_named_type_destroy(n); return tsf_true; } tsf_named_type_t *tsf_type_table_find_by_name(tsf_type_table_t *tt, const char *name) { tsf_named_type_t *n; if (!tsf_st_lookup(tt->ele_table, (char*)name, (void**)&n)) { tsf_set_error(TSF_E_ELE_NOT_FOUND, "Could not find \'%s\'", name); return tsf_false; } return n; } tsf_named_type_t *tsf_type_table_find_by_index(tsf_type_table_t *tt, uint32_t index) { return tt->elements[index]; } uint32_t tsf_type_table_get_num_elements(tsf_type_table_t *tt) { return tt->num_elements; }