/* * Copyright (C) 2003, 2004, 2005, 2011, 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. */ #ifndef FP_TSF_INTERNAL_H #define FP_TSF_INTERNAL_H #include "tsf_internal_config.h" #include "tsf.h" #include #include #include #include "tsf_inttypes.h" /* define all of the structs that were left opaque in tsf.h. */ struct tsf_type_table { tsf_named_type_t **elements; uint32_t num_elements; tsf_st_table *ele_table; }; struct tsf_type_in_map { void *region; /* NULL if not allocated in a region */ tsf_type_t **elements; uint32_t num_elements; uint32_t capacity; }; struct tsf_ra_type_info { uint32_t type_code; uint64_t ref_count; }; struct tsf_ra_tc_node { uint32_t type_code; tsf_ra_tc_node_t *next; }; struct tsf_ra_type_man { tsf_ra_tc_node_t *type_codes; tsf_st_table *out_map; tsf_st_table *in_map; }; struct tsf_type { tsf_type_kind_t kind_code; /* true if this is an ANY or if is a container that contains an ANY. */ tsf_bool_t is_dynamic; union { /* additional data for array */ struct { tsf_type_t *element_type; } a; /* additional data for struct */ struct { /* struct mapping support - need to know the size of * the struct in memory. this is NOT the sum of the * sizes of the elements, because that doesn't take * into account padding or the possibility of additional * fields in that struct that the user isn't telling us * about. HOWEVER! we can be sure that this size must * be greater than or equal to the sum of the sizes of * the elements. */ tsf_bool_t has_size; size_t size; void (*constructor)(void *); void (*pre_destructor)(void *); void (*destructor)(void *); tsf_type_table_t *tt; } s; /* additional data for choice */ struct { tsf_type_table_t *tt; /* struct mapping support */ tsf_bool_t has_mapping; tsf_bool_t in_place; /* use union? */ tsf_bool_t choice_as_full_word; /* use full 32-bit word for emitting the choice. */ size_t value_offset; /* offset to the value field */ size_t data_offset; /* offset to the union if in_place is true, or to the pointer if it is false. */ size_t size; /* size of the choice structure */ } h; } u; /* precomputed hash code. since each tsf_type object is immutable * (that's why all functions that 'modify' a tsf_type actually take * a pointer to a pointer to a tsf_type - so that instead of modifying * the actual tsf_type, it allocates a new one and changes your * pointer), the hash code can safely be precomputed when the * tsf_type is created. */ int hash_code; /* lazily computed type size in bytes. if it hasn't been computed yet, * its value will be 0. */ volatile uint32_t byte_size; /* holder for an optional comment supplied by the user. only * commentable types can hold comments (use tsf_type_kind_is_commentable() * to find out if it is commentable). the comment is a UTF-8 string * supplied by the user via a function call (see tsf_type_set_comment()) * or by using javadoc comments in definitions passed to tsf_define. */ char *comment; /* holder for an optional type name supplied by the user. only * commentable types can have names (use tsf_type_kind_is_commentable() * to find out if it is commentable). the name is a UTF-8 string * supplied by the user via a function call (see tsf_type_set_name()). * types defined using tsf_define automatically have names. */ char *name; /* optional version number for a type. the default value is 0. * this is actually an encoding of major.minor.patch, where major * is a uint16_t, minor is a uint8_t, and patch is a uint8_t. * this can only be changed for commentable types (use * tsf_type_kind_is_commentable() to find out if it is commentable). */ uint32_t version; /* only used for non-singletons */ tsf_atomic_count_t ref_count; /* for memoization: points at the memo master. may be NULL, indicating * that we haven't ever memoized this type. may point to self, * indicating that this is the memo master. */ tsf_type_t *memo_master; }; struct tsf_named_type { char *name; tsf_type_t *type; uint32_t index; /* for struct entries - struct entries may be marked optional. note * that if we have structure A, B, and C, so that A does not have * field F, B has an optional field F, and C has field F, then, assuming * the structs are otherwise equal, the instanceof 'matrix' goes as * follows: * * A B C * A Y Y N * B Y Y N * C Y Y Y * * In other words, a structure with an optional F is not instanceof a * structure with a mandatory F. */ tsf_bool_t optional; /* struct mapping support - need to know the offset of this * element within its parent struct. * * Note that this does not apply to choice types, where * all elements have the same offset. */ tsf_bool_t has_offset; size_t offset; /* holder for an optional comment supplied by the user either through * a function call or through tsf_define. */ char *comment; }; struct tsf_buffer { tsf_type_t *type; tsf_type_in_map_t *types; tsf_bool_t keep; void *data; uint32_t size; tsf_atomic_count_t ref_count; }; struct tsf_reflect { tsf_type_t *type; union { /* container, used for both struct and array. note that it * is used differently for struct and for array. */ struct { tsf_reflect_t **array; uint32_t size; } c; /* choice data. */ struct { uint32_t choice; /* 'unknown' if equal to UINT32_MAX */ tsf_reflect_t *data; } h; /* string data. */ char *str; /* primitives */ int8_t p_int8_t; uint8_t p_uint8_t; int16_t p_int16_t; uint16_t p_uint16_t; int32_t p_int32_t; uint32_t p_uint32_t; int64_t p_int64_t; uint64_t p_uint64_t; tsf_integer_t p_integer; tsf_long_t p_long; float p_float; double p_double; /* bit */ tsf_bool_t bit; /* for the any type */ tsf_buffer_t *any; } u; }; struct tsf_genrtr { tsf_type_t *type; gpc_program_t *generator; }; struct tsf_parser { tsf_type_t *expected_type; size_t expected_type_size; tsf_st_table *parsers; gpc_program_t *cached_program; tsf_type_t *cached_type; tsf_mutex_t lock; }; struct tsf_copier { gpc_program_t *copier; }; struct tsf_destructor { gpc_program_t *destructor; }; typedef struct { tsf_type_cback_t cback; void *arg; } tsf_serial_in_man_cback_t; struct tsf_serial_in_man { tsf_type_in_map_t *types; tsf_serial_in_man_state_t state; uint32_t types_byte_size; tsf_serial_in_man_cback_t *cbacks; uint32_t num_cbacks; tsf_reader_t reader; void *arg; tsf_limits_t *limits; }; struct tsf_serial_out_man { tsf_type_out_map_t *types; tsf_writer_t writer; void *arg; }; struct tsf_sha1_wtr { tsf_SHA1Context ctx; }; struct tsf_buf_rdr { int fd; tsf_bool_t keep_fd; uint8_t *buf; uint32_t size; uint32_t puti; uint32_t geti; }; struct tsf_buf_wtr { int fd; tsf_bool_t keep_fd; uint8_t *buf; uint32_t size; uint32_t pos; }; struct tsf_zip_rdr { tsf_zip_mode_t mode; tsf_partial_reader_t reader; void *reader_arg; void *stream; /* can be either of type z_stream or bz_stream */ tsf_zip_abstract_t abstract; tsf_bool_t decomp_eof; /* true if the decompression algorithm has * reached EOF. */ uint8_t *buf; uint32_t buf_size; }; struct tsf_zip_wtr { tsf_zip_mode_t mode; tsf_writer_t writer; void *writer_arg; void *stream; /* can be either of type z_stream of bz_stream */ tsf_zip_abstract_t abstract; uint8_t *buf; uint32_t buf_size; }; struct tsf_adpt_rdr { tsf_zip_mode_t mode; tsf_partial_reader_t reader; void *reader_arg; void *stream; /* can be either of type z_stream or bz_stream */ tsf_zip_abstract_t abstract; tsf_bool_t expect_switch; uint8_t *buf; uint32_t puti,geti; /* same as in buffered reader */ uint32_t buf_size; tsf_zip_rdr_attr_t attr; uint32_t nozip_buf_size; }; struct tsf_stream_file_input { int fd; tsf_bool_t keep_fd; tsf_serial_in_man_t *in_man; tsf_bool_t use_adpt; union { tsf_buf_rdr_t *buf; tsf_adpt_rdr_t *adpt; void *ptr; } reader; }; struct tsf_stream_file_output { int fd; tsf_bool_t keep_fd; tsf_serial_out_man_t *out_man; tsf_bool_t use_zip; union { tsf_buf_wtr_t *buf; tsf_zip_wtr_t *zip; void *ptr; } writer; tsf_bool_t all_good; }; struct tsf_fsdb_connection { int fd; tsf_bool_t clear; tsf_stream_file_input_t *in; tsf_stream_file_output_t *out; uint8_t *buf; uint32_t buf_size; uint32_t buf_cursor; }; struct tsf_fsdb { tsf_fsdb_kind_t kind; union { struct { DIR *dirhandle; const char *dirname; tsf_bool_t update; tsf_bool_t truncate; uint64_t create_cnt; } local; struct { #ifdef TSF_HAVE_BSDSOCKS /* FIXME: open_remote() should attempt to connect just to see which * address works. it should leave that connection open until the * first put/get request. and it should leave enough info in here * to make subsequent connection requests possible. */ #ifdef TSF_HAVE_GETADDRINFO struct addrinfo *result; struct addrinfo *cur; #else uint32_t addr; int port; #endif tsf_fsdb_connection_t *connection; #endif } remote; } u; tsf_limits_t *limits; tsf_zip_rdr_attr_t rdr_attr; tsf_zip_wtr_attr_t wtr_attr; tsf_mutex_t lock; }; struct tsf_fsdb_response_s; struct tsf_fsdb_in { tsf_fsdb_t *db; union { struct { tsf_buffer_t *key; tsf_stream_file_input_t *in; } local; struct { tsf_fsdb_connection_t *connection; struct tsf_fsdb_response_s *rsp; uint32_t rsp_cursor; tsf_serial_in_man_t *in_man; } remote; } u; }; struct tsf_fsdb_out { tsf_fsdb_t *db; union { struct { char *partname; tsf_buffer_t *key; tsf_stream_file_output_t *out; } local; struct { tsf_fsdb_connection_t *connection; tsf_serial_out_man_t *out_man; } remote; } u; }; /* min and max */ #define tsf_min(a,b) ((a)<(b)?(a):(b)) #define tsf_max(a,b) ((a)>(b)?(a):(b)) /* timestamping */ #ifdef HAVE_GETTIMEOFDAY static TSF_inline int64_t tsf_cur_time(void) { int64_t result; struct timeval tv; gettimeofday(&tv,NULL); result=tv.tv_sec; result*=1000; result*=1000; result+=tv.tv_usec; result*=1000; return result; } #else static TSF_inline int64_t tsf_cur_time(void) { return ((int64_t)time(NULL))*(1000*1000*1000); } #endif /* the full error setting command */ void tsf_set_error_fullv(tsf_error_t code, int sys_errno, int deadly_signal, int zlib_error, const char *zlib_msg, const char *format, va_list lst); void tsf_set_error_full(tsf_error_t code, int sys_errno, int deadly_signal, int zlib_error, const char *zlib_msg, const char *format, ...); /* this is an strerror thingy for zlib. it will abort if called when * no zlib support is compiled. */ const char *tsf_zlib_strerror(int code); /* this is an strerror thingy for libbzip2. it will abort if called * when no libbzip2 support is compiled. */ const char *tsf_libbzip2_strerror(int code); /* this is just plain dumb. thanks a lot, GNU ppl. */ #if defined(HAVE_STPCPY) && !defined(stpcpy) char *stpcpy(char *dest,const char *src); #endif /* tsf_sort just calls qsort if available. otherwise it is some shitty * sorting algo that I implemented. */ void tsf_sort(void *base,size_t nmemb,size_t size, int (*compar)(const void *a,const void *b)); /* sorts an array of uint32_t in ascending order. */ void tsf_ui32_sort(uint32_t *base,size_t nmemb); /* string creation stuff. on error, both functions just set errno. */ char *tsf_vasprintf(const char *format,va_list lst); char *tsf_asprintf(const char *format,...); /* hashtable stuff */ tsf_st_table *tsf_st_init_typetable(); /* limits stuff */ /* max number of types in one stream */ #define tsf_limits_max_types(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_types) /* maximum size in bytes of a serialized type */ #define tsf_limits_max_type_size(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_type_size) /* maximum total size of all types read in a session */ #define tsf_limits_max_total_type_size(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_total_type_size) /* maximum size in bytes of a buffer */ #define tsf_limits_max_buf_size(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_buf_size) /* container depth limit */ #define tsf_limits_depth_limit(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->depth_limit) /* comments */ #define tsf_limits_allow_comments(limits) \ ((limits)==NULL?tsf_true:(limits)->allow_comments) /* maximum array length */ #define tsf_limits_max_array_length(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_array_length) /* maximum struct size, in number of elements */ #define tsf_limits_max_struct_size(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_struct_size) /* maximum choice size, in number of elements */ #define tsf_limits_max_choice_size(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_choice_size) /* maximum string size */ #define tsf_limits_max_string_size(limits) \ ((limits)==NULL?UINT32_MAX:(limits)->max_string_size) /* endianness stuff */ /* get ntohl, htonl, ntohs, htons */ #ifdef HAVE_ARPA_INET_H #include #else #ifdef HAVE_LITTLE_ENDIAN static inline uint32_t ntohl(uint32_t x) { union { uint32_t x; uint8_t c[4]; } u; u.x=x; u.c[0]^=u.c[3]^=u.c[0]^=u.c[3]; u.c[1]^=u.c[2]^=u.c[1]^=u.c[2]; return u.x; } static inline uint16_t ntohs(uint16_t x) { union { uint16_t x; uint8_t c[2]; } u; u.x=x; u.c[0]^=u.c[1]^=u.c[0]^=u.c[1]; return u.x; } #define htonl(x) (ntohl(x)) #define htons(x) (ntohs(x)) #else #define ntohl(x) (x) #define htonl(x) (x) #define ntohs(x) (x) #define htons(x) (x) #endif #endif /* define stupid trivial stuff */ #define htonc(x) (x) #define ntohc(x) (x) #ifdef HAVE_BIG_ENDIAN /* #undef NEED_INT_CONVERSION */ /* define long long equivalent of the arpa/inet functions */ #ifndef htonll #define htonll(x) (x) #endif /* define misaligned copy equivalents of all of the arpa/inet functions */ static inline void copy_htonc(uint8_t *dst, uint8_t *src) { *dst=*src; } static inline void copy_htons(uint8_t *dst, uint8_t *src) { #ifdef CAN_DO_MISALIGNED_LDST *((uint16_t*)dst)=*((uint16_t*)src); #else dst[0]=src[0]; dst[1]=src[1]; #endif } static inline void copy_htonl(uint8_t *dst, uint8_t *src) { #ifdef CAN_DO_MISALIGNED_LDST uint32_t tmp=*((uint32_t*)src); *((uint32_t*)dst)=tmp; #else dst[0]=src[0]; dst[1]=src[1]; dst[2]=src[2]; dst[3]=src[3]; #endif } static inline void copy_htonll(uint8_t *dst, uint8_t *src) { #ifdef CAN_DO_MISALIGNED_LDST *((uint64_t*)dst)=*((uint64_t*)src); #else dst[0]=src[0]; dst[1]=src[1]; dst[2]=src[2]; dst[3]=src[3]; dst[4]=src[4]; dst[5]=src[5]; dst[6]=src[6]; dst[7]=src[7]; #endif } #define copy_ntohc(dst,src) copy_htonc(dst,src) #define copy_ntohs(dst,src) copy_htons(dst,src) #define copy_ntohl(dst,src) copy_htonl(dst,src) #define copy_ntohll(dst,src) copy_htonll(dst,src) #else #define NEED_INT_CONVERSION #ifndef htonll /* define long long equivalent of the arpa/inet functions */ static inline uint64_t htonll(uint64_t x) { /* probably not very efficient, but oh well. */ return ((x >> 56) & UINT64_C(0x00000000000000ff)) | ((x >> 40) & UINT64_C(0x000000000000ff00)) | ((x >> 24) & UINT64_C(0x0000000000ff0000)) | ((x >> 8) & UINT64_C(0x00000000ff000000)) | ((x << 8) & UINT64_C(0x000000ff00000000)) | ((x << 24) & UINT64_C(0x0000ff0000000000)) | ((x << 40) & UINT64_C(0x00ff000000000000)) | ((x << 56) & UINT64_C(0xff00000000000000)); } #endif /* #ifndef htonll */ /* define misaligned copy equivalents of all of the arpa/inet functsions */ static inline void copy_htonc(uint8_t *dst, uint8_t *src) { *dst=*src; } static inline void copy_htons(uint8_t *dst, uint8_t *src) { dst[0]=src[1]; dst[1]=src[0]; } static inline void copy_htonl(uint8_t *dst, uint8_t *src) { dst[0]=src[3]; dst[1]=src[2]; dst[2]=src[1]; dst[3]=src[0]; } static inline void copy_htonll(uint8_t *dst, uint8_t *src) { dst[0]=src[7]; dst[1]=src[6]; dst[2]=src[5]; dst[3]=src[4]; dst[4]=src[3]; dst[5]=src[2]; dst[6]=src[1]; dst[7]=src[0]; } #define copy_ntohc(dst,src) copy_htonc(dst,src) #define copy_ntohs(dst,src) copy_htons(dst,src) #define copy_ntohl(dst,src) copy_htonl(dst,src) #define copy_ntohll(dst,src) copy_htonll(dst,src) #endif #ifndef ntohll #define ntohll(x) (htonll(x)) #endif /* floating point stuff */ #ifdef TSF_HAVE_IEEE_FLOAT #ifdef NEED_INT_CONVERSION #define NEED_FLOAT_CONVERSION #endif static inline float htonf(float x) { uint32_t ret=htonl(*((long*)&x)); return *((float*)&ret); } static inline double htond(double x) { uint64_t ret=htonll(*((uint64_t*)&x)); return *((double*)&ret); } #define ntohf(x) (htonf(x)) #define ntohd(x) (htond(x)) #if !defined(NEED_INT_CONVERSION) &&\ defined(CAN_DO_MISALIGNED_LDST) &&\ !defined(CAN_DO_FLOAT_MISALIGNED_LDST) static inline void copy_htonf(uint8_t *dst, uint8_t *src) { dst[0]=src[0]; dst[1]=src[1]; dst[2]=src[2]; dst[3]=src[3]; } static inline void copy_htond(uint8_t *dst, uint8_t *src) { dst[0]=src[0]; dst[1]=src[1]; dst[2]=src[2]; dst[3]=src[3]; dst[4]=src[4]; dst[5]=src[5]; dst[6]=src[6]; dst[7]=src[7]; } #else #define copy_htonf(dst,src) copy_htonl(dst,src) #define copy_htond(dst,src) copy_htonll(dst,src) #endif #define copy_ntohf(dst,src) copy_htonf(dst,src) #define copy_ntohd(dst,src) copy_htond(dst,src) #else #define NEED_FLOAT_CONVERSION #error "Currently, we only support IEEE floats!" #endif #if defined(NEED_FLOAT_CONVERSION) || defined(NEED_INT_COVERSION) #define NEED_CONVERSION #endif /* destination-incrementing misaligned copy macros. these do * no bounds checking. */ #define copy_htonc_incdst(dst,src) do { \ copy_htonc(dst,src); \ (dst)=(void*)(((uint8_t*)(dst))+1); \ } while (0) #define copy_ntohc_incdst(dst,src) do { \ copy_ntohc(dst,src); \ (dst)=(void*)(((uint8_t*)(dst))+1); \ } while (0) #define copy_htons_incdst(dst,src) do { \ copy_htons(dst,src); \ (dst)=(void*)(((uint16_t*)(dst))+1); \ } while (0) #define copy_ntohs_incdst(dst,src) do { \ copy_ntohs(dst,src); \ (dst)=(void*)(((uint16_t*)(dst))+1); \ } while (0) #define copy_htonl_incdst(dst,src) do { \ copy_htonl(dst,src); \ (dst)=(void*)(((uint32_t*)(dst))+1); \ } while (0) #define copy_ntohl_incdst(dst,src) do { \ copy_ntohl(dst,src); \ (dst)=(void*)(((uint32_t*)(dst))+1); \ } while (0) #define copy_htonll_incdst(dst,src) do { \ copy_htonll(dst,src); \ (dst)=(void*)(((uint64_t*)(dst))+1); \ } while (0) #define copy_ntohll_incdst(dst,src) do { \ copy_ntohll(dst,src); \ (dst)=(void*)(((uint64_t*)(dst))+1); \ } while (0) #define copy_htonf_incdst(dst,src) do { \ copy_htonf(dst,src); \ (dst)=(void*)(((float*)(dst))+1); \ } while (0) #define copy_ntohf_incdst(dst,src) do { \ copy_ntohf(dst,src); \ (dst)=(void*)(((float*)(dst))+1); \ } while (0) #define copy_htond_incdst(dst,src) do { \ copy_htond(dst,src); \ (dst)=(void*)(((double*)(dst))+1); \ } while (0) #define copy_ntohd_incdst(dst,src) do { \ copy_ntohd(dst,src); \ (dst)=(void*)(((double*)(dst))+1); \ } while (0) /* source-incrementing misaligned copy macros. these do * no bounds checking. */ #define copy_htonc_incsrc(dst,src) do { \ copy_htonc(dst,src); \ (src)=(void*)(((uint8_t*)(src))+1); \ } while (0) #define copy_ntohc_incsrc(dst,src) do { \ copy_ntohc(dst,src); \ (src)=(void*)(((uint8_t*)(src))+1); \ } while (0) #define copy_htons_incsrc(dst,src) do { \ copy_htons(dst,src); \ (src)=(void*)(((uint16_t*)(src))+1); \ } while (0) #define copy_ntohs_incsrc(dst,src) do { \ copy_ntohs(dst,src); \ (src)=(void*)(((uint16_t*)(src))+1); \ } while (0) #define copy_htonl_incsrc(dst,src) do { \ copy_htonl(dst,src); \ (src)=(void*)(((uint32_t*)(src))+1); \ } while (0) #define copy_ntohl_incsrc(dst,src) do { \ copy_ntohl(dst,src); \ (src)=(void*)(((uint32_t*)(src))+1); \ } while (0) #define copy_htonll_incsrc(dst,src) do { \ copy_htonll(dst,src); \ (src)=(void*)(((uint64_t*)(src))+1); \ } while (0) #define copy_ntohll_incsrc(dst,src) do { \ copy_ntohll(dst,src); \ (src)=(void*)(((uint64_t*)(src))+1); \ } while (0) #define copy_htonf_incsrc(dst,src) do { \ copy_htonf(dst,src); \ (src)=(void*)(((float*)(src))+1); \ } while (0) #define copy_ntohf_incsrc(dst,src) do { \ copy_ntohf(dst,src); \ (src)=(void*)(((float*)(src))+1); \ } while (0) #define copy_htond_incsrc(dst,src) do { \ copy_htond(dst,src); \ (src)=(void*)(((double*)(src))+1); \ } while (0) #define copy_ntohd_incsrc(dst,src) do { \ copy_ntohd(dst,src); \ (src)=(void*)(((double*)(src))+1); \ } while (0) /* source-incrementing misaligned copy macros. these do * bounds checks. when a bounds check fails, they jump to * the label you give them. */ #define copy_htonc_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<1) { \ goto label; \ } \ copy_htonc(dst,src); \ (src)=(void*)(((uint8_t*)(src))+1); \ } while (0) #define copy_ntohc_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<1) { \ goto label; \ } \ copy_ntohc(dst,src); \ (src)=(void*)(((uint8_t*)(src))+1); \ } while (0) #define copy_htons_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<2) { \ goto label; \ } \ copy_htons(dst,src); \ (src)=(void*)(((uint16_t*)(src))+1); \ } while (0) #define copy_ntohs_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<2) { \ goto label; \ } \ copy_ntohs(dst,src); \ (src)=(void*)(((uint16_t*)(src))+1); \ } while (0) #define copy_htonl_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \ goto label; \ } \ copy_htonl(dst,src); \ (src)=(void*)(((uint32_t*)(src))+1); \ } while (0) #define copy_ntohl_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \ goto label; \ } \ copy_ntohl(dst,src); \ (src)=(void*)(((uint32_t*)(src))+1); \ } while (0) #define copy_htonll_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \ goto label; \ } \ copy_htonll(dst,src); \ (src)=(void*)(((uint64_t*)(src))+1); \ } while (0) #define copy_ntohll_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \ goto label; \ } \ copy_ntohll(dst,src); \ (src)=(void*)(((uint64_t*)(src))+1); \ } while (0) #define copy_htonf_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \ goto label; \ } \ copy_htonf(dst,src); \ (src)=(void*)(((float*)(src))+1); \ } while (0) #define copy_ntohf_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \ goto label; \ } \ copy_ntohf(dst,src); \ (src)=(void*)(((float*)(src))+1); \ } while (0) #define copy_htond_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \ goto label; \ } \ copy_htond(dst,src); \ (src)=(void*)(((double*)(src))+1); \ } while (0) #define copy_ntohd_incsrc_bc(dst,src,end,label) do { \ if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \ goto label; \ } \ copy_ntohd(dst,src); \ (src)=(void*)(((double*)(src))+1); \ } while (0) static inline size_t size_of_tsf_integer(tsf_integer_t src) { if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) { return 1; } if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) { return 2; } if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) { return 4; } return 5; } static inline size_t size_of_tsf_unsigned(tsf_unsigned_t src) { if (src < TSF_UNSIGNED_SMALL_LIM) { return 1; } if (src < TSF_UNSIGNED_MEDIUM_LIM) { return 2; } if (src < TSF_UNSIGNED_LARGE_LIM) { return 4; } return 5; } static inline size_t size_of_tsf_long(tsf_long_t src) { if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) { return 1; } if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) { return 2; } if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) { return 4; } return 9; } static inline size_t write_tsf_integer(uint8_t *dst, tsf_integer_t src) { if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) { dst[0] = ((uint8_t)(int8_t)src) & ~TSF_INTEGER_MEDIUM_BIT; return 1; } /* FIXME: The remainder of this function could be an out-of-line slow path. */ if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) { if (src < 0) { src += TSF_INTEGER_SMALL_LIM; } else { src -= TSF_INTEGER_SMALL_LIM; } dst[0] = (((int8_t)((src >> 8) & 255)) - TSF_INTEGER_MEDIUM_DIFF) | TSF_INTEGER_MEDIUM_BIT; dst[1] = src & 255; return 2; } if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) { if (src < 0) { src += TSF_INTEGER_MEDIUM_LIM; } else { src -= TSF_INTEGER_MEDIUM_LIM; } dst[0] = TSF_INTEGER_LARGE_TAG; dst[1] = (src >> 16) & 255; dst[2] = (src >> 8) & 255; dst[3] = src & 255; return 4; } dst[0] = TSF_INTEGER_HUGE_TAG; dst[1] = (src >> 24) & 255; dst[2] = (src >> 16) & 255; dst[3] = (src >> 8) & 255; dst[4] = src & 255; return 5; } static inline size_t write_tsf_unsigned(uint8_t *dst, tsf_unsigned_t src) { if (src < TSF_UNSIGNED_SMALL_LIM) { dst[0] = src; return 1; } /* FIXME: The remainder of this function could be an out-of-line slow path. */ if (src < TSF_UNSIGNED_MEDIUM_LIM) { src -= TSF_UNSIGNED_SMALL_LIM; dst[0] = ((src >> 8) & 255) | TSF_UNSIGNED_MEDIUM_BIT; dst[1] = src & 255; return 2; } if (src < TSF_UNSIGNED_LARGE_LIM) { src -= TSF_UNSIGNED_MEDIUM_LIM; dst[0] = TSF_UNSIGNED_LARGE_TAG; dst[1] = (src >> 16) & 255; dst[2] = (src >> 8) & 255; dst[3] = src & 255; return 4; } dst[0] = TSF_UNSIGNED_HUGE_TAG; dst[1] = (src >> 24) & 255; dst[2] = (src >> 16) & 255; dst[3] = (src >> 8) & 255; dst[4] = src & 255; return 5; } static inline size_t write_tsf_long(uint8_t *dst, tsf_long_t src) { if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) { dst[0] = ((uint8_t)(int8_t)src) & ~TSF_INTEGER_MEDIUM_BIT; return 1; } /* FIXME: The remainder of this function could be an out-of-line slow path. */ if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) { if (src < 0) { src += TSF_INTEGER_SMALL_LIM; } else { src -= TSF_INTEGER_SMALL_LIM; } dst[0] = (((int8_t)((src >> 8) & 255)) - TSF_INTEGER_MEDIUM_DIFF) | TSF_INTEGER_MEDIUM_BIT; dst[1] = src & 255; return 2; } if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) { if (src < 0) { src += TSF_INTEGER_MEDIUM_LIM; } else { src -= TSF_INTEGER_MEDIUM_LIM; } dst[0] = TSF_INTEGER_LARGE_TAG; dst[1] = (src >> 16) & 255; dst[2] = (src >> 8) & 255; dst[3] = src & 255; return 4; } dst[0] = TSF_INTEGER_HUGE_TAG; dst[1] = (src >> 56) & 255; dst[2] = (src >> 48) & 255; dst[3] = (src >> 40) & 255; dst[4] = (src >> 32) & 255; dst[5] = (src >> 24) & 255; dst[6] = (src >> 16) & 255; dst[7] = (src >> 8) & 255; dst[8] = src & 255; return 9; } static inline size_t size_of_encoded_tsf_integer(int8_t value) { if (!(value & TSF_INTEGER_MEDIUM_BIT)) { return 1; } switch (value) { case TSF_INTEGER_LARGE_TAG: return 4; case TSF_INTEGER_HUGE_TAG: return 5; default: return 2; } } static inline size_t size_of_encoded_tsf_unsigned(uint8_t value) { if (!(value & TSF_UNSIGNED_MEDIUM_BIT)) { return 1; } switch (value) { case TSF_UNSIGNED_LARGE_TAG: return 4; case TSF_UNSIGNED_HUGE_TAG: return 5; default: return 2; } } static inline size_t size_of_encoded_tsf_long(int8_t value) { if (!(value & TSF_INTEGER_MEDIUM_BIT)) { return 1; } switch (value) { case TSF_INTEGER_LARGE_TAG: return 4; case TSF_INTEGER_HUGE_TAG: return 9; default: return 2; } } static inline size_t read_tsf_integer(tsf_integer_t *dst, uint8_t *src, size_t src_remaining) { if (!src_remaining) return 0; int8_t head_value = src[0]; if (!(head_value & TSF_INTEGER_MEDIUM_BIT)) { *dst = ((int8_t)(head_value << 1)) >> 1; return 1; } /* FIXME: The remainder of this function could be an out-of-line slow path. */ switch (head_value) { case TSF_INTEGER_LARGE_TAG: { if (src_remaining < 4) return 0; int32_t value = (((int32_t)(int8_t)src[1]) << 16) | (((int32_t)(uint32_t)src[2]) << 8) | ((int32_t)(uint32_t)src[3]); if (value < 0) value -= TSF_INTEGER_MEDIUM_LIM; else value += TSF_INTEGER_MEDIUM_LIM; *dst = value; return 4; } case TSF_INTEGER_HUGE_TAG: { if (src_remaining < 5) return 0; int32_t value = (((int32_t)(int8_t)src[1]) << 24) | (((int32_t)(uint32_t)src[2]) << 16) | (((int32_t)(uint32_t)src[3]) << 8) | ((int32_t)(uint32_t)src[4]); *dst = value; return 5; } default: { if (src_remaining < 2) return 0; int32_t value = ((int32_t)(uint32_t)src[1]) | (((int32_t)((((int8_t)(head_value << 1)) >> 1) + TSF_INTEGER_MEDIUM_DIFF)) << 8); if (value < 0) value -= TSF_INTEGER_SMALL_LIM; else value += TSF_INTEGER_SMALL_LIM; *dst = value; return 2; } } } static inline size_t read_tsf_unsigned(tsf_unsigned_t *dst, uint8_t *src, size_t src_remaining) { if (!src_remaining) return 0; uint8_t head_value = src[0]; if (!(head_value & TSF_UNSIGNED_MEDIUM_BIT)) { *dst = head_value; return 1; } /* FIXME: The remainder of this function could be an out-of-line slow path. */ switch (head_value) { case TSF_UNSIGNED_LARGE_TAG: { if (src_remaining < 4) return 0; int32_t value = (((int32_t)(int8_t)src[1]) << 16) | (((int32_t)(uint32_t)src[2]) << 8) | ((int32_t)(uint32_t)src[3]); value += TSF_UNSIGNED_MEDIUM_LIM; *dst = value; return 4; } case TSF_UNSIGNED_HUGE_TAG: { if (src_remaining < 5) return 0; int32_t value = (((int32_t)(int8_t)src[1]) << 24) | (((int32_t)(uint32_t)src[2]) << 16) | (((int32_t)(uint32_t)src[3]) << 8) | ((int32_t)(uint32_t)src[4]); *dst = value; return 5; } default: { if (src_remaining < 2) return 0; int32_t value = ((int32_t)(uint32_t)src[1]) | ((head_value & ~TSF_UNSIGNED_MEDIUM_BIT) << 8); value += TSF_UNSIGNED_SMALL_LIM; *dst = value; return 2; } } } static inline size_t read_tsf_long(tsf_long_t *dst, uint8_t *src, size_t src_remaining) { if (!src_remaining) return 0; int8_t head_value = src[0]; if (!(head_value & TSF_INTEGER_MEDIUM_BIT)) { *dst = ((int8_t)(head_value << 1)) >> 1; return 1; } /* FIXME: The remainder of this function could be an out-of-line slow path. */ switch (head_value) { case TSF_INTEGER_LARGE_TAG: { if (src_remaining < 4) return 0; int64_t value = (((int64_t)(int8_t)src[1]) << 16) | (((int64_t)(uint64_t)src[2]) << 8) | ((int64_t)(uint64_t)src[3]); if (value < 0) value -= TSF_INTEGER_MEDIUM_LIM; else value += TSF_INTEGER_MEDIUM_LIM; *dst = value; return 4; } case TSF_INTEGER_HUGE_TAG: { if (src_remaining < 9) return 0; int64_t value = (((int64_t)(int8_t)src[1]) << 56) | (((int64_t)(uint64_t)src[2]) << 48) | (((int64_t)(uint64_t)src[3]) << 40) | (((int64_t)(uint64_t)src[4]) << 32) | (((int64_t)(uint64_t)src[5]) << 24) | (((int64_t)(uint64_t)src[6]) << 16) | (((int64_t)(uint64_t)src[7]) << 8) | ((int64_t)(uint64_t)src[8]); *dst = value; return 9; } default: { if (src_remaining < 2) return 0; int64_t value = ((int64_t)(uint64_t)src[1]) | (((int64_t)((((int8_t)(head_value << 1)) >> 1) + TSF_INTEGER_MEDIUM_DIFF)) << 8); if (value < 0) value -= TSF_INTEGER_SMALL_LIM; else value += TSF_INTEGER_SMALL_LIM; *dst = value; return 2; } } } #define read_tsf_integer_incsrc(dst, src, end, bounds_error) do { \ size_t total_bytes_read = \ read_tsf_integer((dst), (src), (end) - (src)); \ if (!total_bytes_read) { \ goto bounds_error; \ } \ \ (src) += total_bytes_read; \ } while (0) #define read_tsf_unsigned_incsrc(dst, src, end, bounds_error) do { \ size_t total_bytes_read = \ read_tsf_unsigned((dst), (src), (end) - (src)); \ if (!total_bytes_read) { \ goto bounds_error; \ } \ \ (src) += total_bytes_read; \ } while (0) #define read_tsf_long_incsrc(dst, src, end, bounds_error) do { \ size_t total_bytes_read = \ read_tsf_long((dst), (src), (end) - (src)); \ if (!total_bytes_read) { \ goto bounds_error; \ } \ \ (src) += total_bytes_read; \ } while (0) static inline size_t skip_string(const char *start, const char *end) { const char *cur = start; for (;;) { if (cur >= end) return 0; if (!*cur) return cur + 1 - start; cur++; } } /* internal recursive function for reading types */ tsf_type_t *tsf_type_read_rec(tsf_reader_t reader, void *arg, tsf_limits_t *limits, uint32_t depth); /* read a type table */ 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); /* clones a type, returning a new one just like it. note this is * actually deep copy. */ tsf_type_t* tsf_type_clone(tsf_type_t *type); /* gives you a version of the given type that you own; i.e. if you make * changes to it in-place then nobody else will notice. this is a O(1) * operation that returns the passed-in type object if it already has a * reference count of 1. otherwise the type is copied using * tsf_type_clone(). */ tsf_type_t* tsf_type_own_begin(tsf_type_t *type); /* commits to an ownership operation by relinquishing our reference to * the original type. */ void tsf_type_own_commit(tsf_type_t **dst, tsf_type_t *ret); /* undoes an ownership operation by deleting the clone if necessary. */ void tsf_type_own_abort(tsf_type_t *dst, tsf_type_t *ret); /* recompute the hash code */ void tsf_type_recompute_hash(tsf_type_t *type); /* create a tsf_buffer in which the caller owns the tsf_buffer object itself and the original backing store. this can be used to read stack-allocated buffers. this must be destroyed with tsf_buffer_destroy_custom(). few functions work on the buffer that this returns. the tsf_buffer_read_simple and tsf_buffer_read_small_with_type_code functions are two functions that do work with custom buffers. note that this really needs to be internal API, since it requires that the caller knows exactly the sizeof(tsf_buffer_t). if we wanted an external vesion of this API, we'd have the user just pass in a backing store and we'd partition it into a tsf_buffer_t and the actual backing store. we'd also kindly report error if the buffer wasn't big enough for a tsf_buffer_t. */ void tsf_buffer_initialize_custom(tsf_buffer_t *buf, void *backing_store, size_t backing_store_size); /* destroy a tsf_buffer created with tsf_buffer_initialize_custom(). */ void tsf_buffer_destroy_custom(tsf_buffer_t *buf); /* create a tsf_buffer that is ready for use with tsf_buffer_read_simple, tsf_buffer_read_small_with_type_code, and the GPC generator. */ tsf_buffer_t *tsf_buffer_create_bare(void); /* create a tsf_buffer that is ready for use with GPC generator with a non-NULL * region. */ tsf_buffer_t *tsf_buffer_create_bare_in(void* region); /* destroy a tsf_buffer that was created with tsf_buffer_create_bare() but didn't yet have anything else done to it. */ void tsf_buffer_destroy_bare(tsf_buffer_t *buf); /* read/write a buffer using the old buffer framing format, which is still * appropriate for large buffers. */ tsf_bool_t tsf_buffer_read_simple(tsf_buffer_t *buf, tsf_type_in_map_t *enclosing_types, tsf_reader_t reader, void *arg, tsf_limits_t *limits); tsf_bool_t tsf_buffer_write_simple(tsf_buffer_t *buf, uint32_t type_code, tsf_type_out_map_t *type_map, tsf_writer_t writer, void *arg); /* read/write a small buffer using the new framing format, which only works * for small buffers. */ tsf_bool_t tsf_buffer_read_small_with_type_code(tsf_buffer_t *buf, uint32_t type_code, tsf_type_in_map_t *enclosing_types, tsf_reader_t reader, void *arg, tsf_limits_t *limits); tsf_bool_t tsf_buffer_write_small_with_type_code(tsf_buffer_t *buf, tsf_type_out_map_t *type_map, tsf_writer_t writer, void *arg); /* read into an already-created buffer. the buffer should have been created using either tsf_buffer_initialize_custom() or tsf_buffer_create_bare() */ tsf_bool_t tsf_serial_in_man_read_existing_buffer(tsf_serial_in_man_t *in_man, tsf_buffer_t *buf); /* read a buffer from a file that was openned for reading using an already-created buffer. */ tsf_bool_t tsf_stream_file_input_read_existing_buffer(tsf_stream_file_input_t *file, tsf_buffer_t *buf); /* generate into an existing buffer created usign tsf_buffer_initialize_custom(). */ tsf_bool_t tsf_generator_generate_existing_buffer(tsf_genrtr_t *gen, void *data, tsf_buffer_t *buf); /* write a type according to the serial protocol */ tsf_bool_t tsf_serial_out_man_write_type(tsf_writer_t writer, void *arg, tsf_type_t *type); /* verify that the data is valid. basically just does NULL checks. */ tsf_bool_t tsf_reflect_verify(tsf_reflect_t *data); /* generate a gpint prototype for a generator. a generator takes * the following arguments on the stack: a pointer to a tsf_type_t, * and a pointer to the user structure. the generator returns a * pointer to a tsf_buffer_t, or 0 if an error occurred. */ gpc_proto_t *tsf_gpc_code_gen_generate_generator(tsf_type_t *type); /* generate a gpint prototype for a parser. a parser takes the * following arguments on the stack: a pointer to a tsf_buffer_t. * it returns a pointer to a user structure that is also a region. */ gpc_proto_t *tsf_gpc_code_gen_generate_parser(tsf_type_t *dest_type, tsf_type_t *src_type); /* generate a gpint prototype for a converter. a converter takes * the following arguments on the stack: a pointer to the destination, * which may be NULL indicating that the destination should be * allocated, and a pointer to the source. the region register * may be NULL only if the destination is NULL; if the region * is NULL it means that a new region should be allocated. a * converter returns the destination. */ gpc_proto_t *tsf_gpc_code_gen_generate_converter(tsf_type_t *dest_type, tsf_type_t *src_type); /* generate a gpint prototype for a destroyer. a destroyer takes the * following arguments on the stack: a pointer to the user structure. * it returns 0. */ gpc_proto_t *tsf_gpc_code_gen_generate_destroyer(tsf_type_t *type); /* internal FSDB put function. just gives you a file descriptor * for writing to the file and the file name. */ tsf_bool_t tsf_fsdb_guts_put(tsf_fsdb_t *fsdb, tsf_buffer_t *key, int *fd, char **partflnm); /* internal FSDB commit function. */ tsf_bool_t tsf_fsdb_guts_commit(tsf_fsdb_t *fsdb, char *partflnm, tsf_buffer_t *key, char **dataflnm); /* internal FSDB abort function. */ tsf_bool_t tsf_fsdb_guts_abort(tsf_fsdb_t *fsdb, char *partflnm); /* internal FSDB get function. */ tsf_bool_t tsf_fsdb_guts_get(tsf_fsdb_t *fsdb, tsf_buffer_t *key, int *fd, char **dataflnm); /* internal FSDB rm function. */ tsf_bool_t tsf_fsdb_guts_rm(tsf_fsdb_t *fsdb, tsf_buffer_t *key, char **dataflnm); /* abort because we screwed up big time */ #define tsf_abort(msg) do { \ fprintf(stderr,"tsf_abort(\"%s\"): called at %s:%d\n", \ msg,__FILE__,__LINE__); \ abort(); \ } while (0) /* function version of abort */ void tsf_f_abort(const char *msg); /* make an assertion that, if it fails, causes us to abort. we don't * support the notion of optional assertions; they are always enabled. */ #define tsf_assert(exp) do { \ if (!(exp)) { \ fprintf(stderr,"tsf_assert(%s): failed at %s:%d\n", \ #exp,__FILE__,__LINE__); \ abort(); \ } \ } while (0) #endif