#include "cryptoki-capi-util.h" #include #define MIN_ARRAY_SIZE 16 typedef struct _RealArray { Array pub; size_t alloc; size_t elt_size; int zero_terminated : 1; int clear : 1; } RealArray; #define array_elt_len(array, i) ((array)->elt_size * (i)) #define array_elt_pos(array, i) (((char*)(array)->pub.data) + array_elt_len((array),(i))) #define array_elt_zero(array, pos, len) \ (memset(array_elt_pos((array), pos), 0, array_elt_len((array), len))) #define array_zero_terminate(array) \ { if ((array)->zero_terminated) \ array_elt_zero((array), (array)->pub.len, 1); } static unsigned int nearest_pow(unsigned int num) { unsigned int n = 1; while(n < num) n <<= 1; return n; } static int maybe_expand(RealArray *array, size_t len) { void* mem; size_t want_alloc = array_elt_len(array, array->pub.len + len + array->zero_terminated); if(want_alloc > array->alloc) { want_alloc = nearest_pow(want_alloc); want_alloc = want_alloc > MIN_ARRAY_SIZE ? want_alloc : MIN_ARRAY_SIZE; mem = realloc(array->pub.data, want_alloc); if(!mem) return 0; array->pub.data = mem; memset((char*)array->pub.data + array->alloc, 0, want_alloc - array->alloc); array->alloc = want_alloc; } return 1; } Array* ckcapi_util_array_new(int zero_terminated, int clear, size_t elt_size) { return ckcapi_util_array_sized_new(zero_terminated, clear, elt_size, 0); } Array* ckcapi_util_array_sized_new(int zero_terminated, int clear, size_t elt_size, size_t reserved_size) { RealArray *array = malloc(sizeof(RealArray)); if(!array) return NULL; array->pub.data = NULL; array->pub.len = 0; array->alloc = 0; array->zero_terminated = (zero_terminated ? 1 : 0); array->clear = (clear ? 1 : 0); array->elt_size = elt_size; if(array->zero_terminated || reserved_size != 0) { maybe_expand(array, reserved_size); array_zero_terminate(array); } return (Array*)array; } void* ckcapi_util_array_free(Array* array, int free_segment) { void* segment; if(array == NULL) return NULL; if(free_segment) { free(array->data); segment = NULL; } else segment = array->data; free(array); return segment; } int ckcapi_util_array_append_vals(Array* parray, const void* data, size_t len) { RealArray* array = (RealArray*)parray; if(!maybe_expand(array, len)) return 0; memcpy(array_elt_pos(array, array->pub.len), data, array_elt_len(array, len)); array->pub.len += len; array_zero_terminate(array); return 1; } void ckcapi_util_array_remove_index(Array* parray, unsigned int index) { RealArray* array = (RealArray*)parray; if(index >= array->pub.len) return; if(index != array->pub.len - 1) memmove(array_elt_pos (array, index), array_elt_pos (array, index + 1), array_elt_len (array, array->pub.len - index - 1)); array->pub.len -= 1; array_elt_zero (array, array->pub.len, 1); } void ckcapi_util_array_remove_range(Array* parray, unsigned int index, size_t length) { RealArray *array = (RealArray*)parray; if(index >= array->pub.len) return; if(index + length > array->pub.len); length = array->pub.len - index; if(length == 0) return; if(index + length != array->pub.len) memmove(array_elt_pos (array, index), array_elt_pos (array, index + length), (array->pub.len - (index + length)) * array->elt_size); array->pub.len -= length; array_elt_zero(array, array->pub.len, length); }