* Copyright (C) 2003, 2004, 2005, 2006, 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.
*/
* Stuff to know:
*
* Memory management conventions: unless otherwise stated, all objects
* allocated by functions that you call become your responsibility after
* a successful return. also, unless otherwise stated, passing an
* object as a first argument to a function does not clear your ownership
* of that object. and unless otherwise stated, objects passed as anything
* but the first argument become the responsibility of that function,
* regardless of whether or not that function returns successfully.
*
* Error management conventions: most functions return pointers or booleans.
* in the case of pointers, if the pointer returned is NULL, then you must
* check for errors. in the case of booleans, you must check if the
* return value is tsf_false.
*
* Error propagation: those functions that claim to be capable of error
* propagation will return immediately as if with an error without actually
* setting the error if one of their object arguments is NULL. This allows
* you to do:
* if (!tsf_do_operation(object1,obj2, ..., tsf_do_op_that_fails(),...)) {
* // process error.
* }
* ... and safely expect that this will correctly catch errors from
* tsf_do_op_that_fails() in addition to catching errors from
* tsf_do_operation().
*
* Code generation/native code support/struct mapping: this functionality is
* captured under the 'tsf_native' namespace, but it does not actually have
* any struct or class or object of its own. Instead, this functionality's
* state is spread across the rest of the system. Fields that have the sole
* purpose of supporting code generation or struct mapping are marked as
* such with a comment.
*/
#ifndef FP_TSF_H
#define FP_TSF_H
#include "tsf_config.h"
#include "tsf_atomics.h"
#include "tsf_st.h"
#include "tsf_region.h"
#include "tsf_types.h"
#include "tsf_zip_abstract.h"
#include "tsf_sha1.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dirent.h>
#ifdef __cplusplus
extern "C" {
#endif
#if 0
}
#endif
#define tsf_offsetof(type,element) ((size_t)(&(((type*)NULL)->element)))
* init_error_array() function. */
enum tsf_error {
TSF_E_ERRNO,
* from tsf_get_system_errno() */
TSF_E_ZLIB_ERROR,
* from tsf_get_zlib_error_code() and also the
* error message returned from
* tsf_get_zlib_error_msg() */
TSF_E_LIBBZIP2_ERROR,
* from tsf_get_libbzip2_error_code() and also the
* error message returned from
* tsf_get_libbzip2_error_msg(). note that the
* latter function returns textual messages
* selected by TSF and not by libbzip2. these
* messages were written by me based on the
* libbzip2 manual. */
TSF_E_INVALID_ARG,
TSF_E_BAD_STATE,
* sense for the current state of the object. */
TSF_E_STR_OVERFLOW,
* in structs and choices cannot be longer than
* TSF_STR_SIZE (including null byte). comment
* strings also have some limit. */
TSF_E_PARSE_ERROR,
TSF_E_UNEXPECTED_TYPE,
* parse. this may happen if you're asking the
* serial in man to re-read some data that it's
* already read. you can do this by using its
* mark and seek mechanism. */
TSF_E_ELEMENT_NULL,
TSF_E_NAME_COLLISION,
TSF_E_EOF,
TSF_E_UNEXPECTED_EOF,
* returned from a reader, this error means that
* the EOF happened before any data was read. */
TSF_E_ERRONEOUS_EOF,
* returned from a reader, this error means that
* the EOF happened after some data was already
* read. to everyone else, this error should
* have the same exact meaning as
* TSF_E_UNEXPECTED_EOF */
TSF_E_NO_EOF,
TSF_E_BAD_TYPE,
* when the type for a typed object (such as
* a reflect object) is not what is expected. */
TSF_E_BAD_TYPE_KIND,
* thrown when you pass the wrong type object
* into a function. */
TSF_E_ELE_NOT_FOUND,
TSF_E_NO_STRUCT_MAP,
TSF_E_BAD_STRUCT_MAP,
* invalid because it does not agree with the
* offsets and/or sizes of the other elements.
* note that this is currently unused, but we
* keep it here to reserve space. */
TSF_E_TYPE_MISMATCH,
TSF_E_BAD_CHOICE_VALUE,
* value appears while parsing, you will get a
* TSF_E_PARSE_ERROR instead. also, there will
* be times when you don't get this error even
* though you should have. so be happy when
* you see it and don't cry to me about it if you
* don't. */
TSF_E_COMPARE_FAIL,
TSF_E_COMPILE_ERROR,
TSF_E_DEATH_BY_SIGNAL,
* signal (again, this'll happen because of
* dyncc). */
TSF_E_DLOADING_ERROR,
TSF_E_BAD_JUMP,
TSF_E_SEMANTIC,
TSF_E_CAS_FAIL,
TSF_E_HOSTNAME,
TSF_E_NOT_ALLOWED,
* a certain action was not allowed, but for
* whatever reason TSF would have had to perform
* that action. */
TSF_E_NOT_IMPLEMENTED,
* supported in that something that is 'not
* implemented' is actually advertised as being
* supported (and implemented), but I just
* haven't moved my ass to implement it. you
* should only see 'not implemented' errors in
* development versions. */
TSF_E_NOT_SUPPORTED,
* implemented in that 'not supported' refers
* to functionality that is present but cannot
* be used due to some limitations of your
* system. */
TSF_E_EXTERNAL,
* in a callback provided by someone else).
* the C++ binding uses this for
* std::exception objects caught in callbacks. */
TSF_E_INTERNAL,
TSF_E_LAST
};
typedef enum tsf_error tsf_error_t;
#define TSF_STR_SIZE 128
#define TSF_MAX_COMMENT_SIZE 4096
#define TSF_MAX_NAME_SIZE 256
#define TSF_DEF_BUF_SIZE 4096
#define TSF_DEF_NET_BUF_SIZE (1460*32)
* -> VOID type. everything is instanceof VOID, but VOID is instaceof
* VOID only.
* -> INT types. An INT type is instanceof any INT type that is
* composed of at least as many bits as it. For example, INT8
* is instanceof INT8, INT16, INT32, and INT64. INT types are
* not instanceof any UINT types. INT types are instanceof
* those FP types that have a mantissa that is made up of at
* least as many bits as it.
* -> UINT types. A UINT type is instanceof any UINT type that is
* composed of at least as many bits as it. Also, a UINT type
* is instanceof any INT type that has at least one more bits
* than it (so UINT16 will be instanceof INT32 and INT64, but
* not INT16). UINT types are instanceof those FP types that
* have a mantissa that is made up of at least one more bits as
* it.
* -> INTEGER. This behaves like a 32-bit signed integer, but it
* is stored with some basic compaction under the assumption
* that it is usually smallish.
* -> LONG. Same as INTEGER, but gives you 64 bits.
* -> FP types. An FP type is instanceof any FP type that has at
* least as large of a mantissa, and at least as large of an
* exponent. So FLOAT is instanceof FLOAT and DOUBLE, while
* DOUBLE is only instanceof DOUBLE.
* -> ARRAY. if A and B are array types, then A is instanceof B
* if element_type(A) is instanceof element_type(B).
* -> STRUCT. one struct is instanceof another if it contains all
* of the mandatory elements of the other struct, and if each
* such element is instanceof its respective element in the other
* struct. note that if a struct contains an optional field for
* another struct's mandatory field, this will violate the
* instanceof relation.
* -> BIT. a BIT is only instanceof BIT. the justification is that
* despite the name, which would seem to imply that a BIT is a
* type of integer, a BIT is intended to be used in such a
* fundamentally different way that it would not make sense for
* a BIT to be instanceof any integer.
* -> CHOICE. if A and B are choice types, then A is instanceof B
* if for those element names that A and B have in common, A's
* element is instanceof B's element.
* -> STRING. a STRING is only instanceof STRING.
* -> ANY. a ANY is only instanceof ANY. this is of
* course quite ironic, since ANY types are our main source of
* polymorhpism. :-)
*
* Note that if you change this enumeration, you must change some of the
* #define's further down in this file.
*/
enum tsf_type_kind {
TSF_TK_VOID = 0,
TSF_TK_INT8 = 1,
TSF_TK_UINT8 = 2,
TSF_TK_INT16 = 3,
TSF_TK_UINT16 = 4,
TSF_TK_INT32 = 5,
TSF_TK_UINT32 = 6,
TSF_TK_INT64 = 7,
TSF_TK_UINT64 = 8,
* (TSF_TK_LONG) that we compact down to 1 byte if possible whenever we
* transmit it. The rules for integer compaction given an integer X are:
*
* - If -64 <= X < 64, encode as one byte containing X with the high bit
* of that byte set to 0. Else:
* - Let X' = (X < 0) ? X + 64 : X - 64. If -16192 <= X < 16192, encode
* as one byte containing (X' >> 8) - 1 with the high bit of that byte
* set to 1 followed by a second byte containing X' & 255. Else:
* - Let X' = (X < 0) ? X + 16192 : X - 16192. If -8404800 <= X < 8404800,
* encode as one byte containing 254 followed by three bytes containing
* X'. Else:
* - Encode as 255 followed by either four bytes (TSF_TK_INTEGER) or
* eight bytes (TSF_TK_LONG) containin X.
*
* Note that as with everything else in TSF, the protocol is defined as
* big endian. */
TSF_TK_INTEGER = 14,
TSF_TK_LONG = 15,
TSF_TK_FLOAT = 20,
TSF_TK_DOUBLE = 21,
* we ever have a customizable float, it should be 30. */
TSF_TK_BIT = 40,
TSF_TK_STRING = 45,
TSF_TK_ARRAY = 50,
TSF_TK_STRUCT = 51,
TSF_TK_CHOICE = 52,
TSF_TK_ANY = 60,
};
typedef uint8_t tsf_type_kind_t;
struct tsf_type;
typedef struct tsf_type tsf_type_t;
struct tsf_named_type;
typedef struct tsf_named_type tsf_named_type_t;
struct tsf_type_table;
typedef struct tsf_type_table tsf_type_table_t;
struct tsf_type_in_map;
typedef struct tsf_type_in_map tsf_type_in_map_t;
typedef tsf_st_table tsf_type_out_map_t;
struct tsf_ra_type_info;
struct tsf_ra_tc_node;
struct tsf_ra_type_man;
typedef struct tsf_ra_type_info tsf_ra_type_info_t;
typedef struct tsf_ra_tc_node tsf_ra_tc_node_t;
typedef struct tsf_ra_type_man tsf_ra_type_man_t;
struct tsf_buffer;
typedef struct tsf_buffer tsf_buffer_t;
* structure mapping. you do not have to ever touch this type. but
* if you do struct mapping (which surely you will!), then your
* arrays should resemble this here tsf_native_array. */
struct tsf_native_array {
void *data;
uint32_t len;
};
typedef struct tsf_native_array tsf_native_array_t;
#define TSF_DEFINE_NATIVE_ARRAY(type,suffix) \
struct tsf_native_##type##_array {\
type##suffix *data;\
uint32_t len;\
};\
\
typedef struct tsf_native_##type##_array tsf_native_##type##_array_t
TSF_DEFINE_NATIVE_ARRAY(int8,_t);
TSF_DEFINE_NATIVE_ARRAY(int16,_t);
TSF_DEFINE_NATIVE_ARRAY(int32,_t);
TSF_DEFINE_NATIVE_ARRAY(int64,_t);
TSF_DEFINE_NATIVE_ARRAY(uint8,_t);
TSF_DEFINE_NATIVE_ARRAY(uint16,_t);
TSF_DEFINE_NATIVE_ARRAY(uint32,_t);
TSF_DEFINE_NATIVE_ARRAY(uint64,_t);
TSF_DEFINE_NATIVE_ARRAY(float,);
TSF_DEFINE_NATIVE_ARRAY(double,);
struct tsf_native_void_array {
uint32_t len;
};
typedef struct tsf_native_void_array tsf_native_void_array_t;
* within our native structure mapping. */
struct tsf_native_bitvector {
uint8_t *bits;
uint32_t num_bits;
};
typedef struct tsf_native_bitvector tsf_native_bitvector_t;
typedef uint32_t tsf_choice_t;
struct tsf_reflect;
typedef struct tsf_reflect tsf_reflect_t;
struct tsf_genrtr;
struct tsf_parser;
struct tsf_copier;
struct tsf_destructor;
typedef struct tsf_genrtr tsf_genrtr_t;
typedef struct tsf_parser tsf_parser_t;
typedef struct tsf_copier tsf_copier_t;
typedef struct tsf_destructor tsf_destructor_t;
* tsf_false on error. on error, use tsf_set_error() and tsf_set_errno()
* to indicate what error occurred (this part is not optional - you
* cannot return tsf_false without first calling tsf_set_error() or
* tsf_set_errno()). an all-or-nothing read is expected, so if you're
* implementing this as a read on a socket or pipe, you may have to
* loop a couple of times. */
typedef tsf_bool_t (*tsf_reader_t)(void *arg,
void *buf,
uint32_t len);
* tsf_false on error. on error, use tsf_set_error() and tsf_set_errno()
* to indicate what error occurred (this part is not optional - you
* cannot return tsf_false without first calling tsf_set_error() or
* tsf_set_errno()). an all-or-nothing write is expected, so if you're
* implementing this as a write on a socket or pipe, you may have to
* loop a couple of times. */
typedef tsf_bool_t (*tsf_writer_t)(void *arg,
const void *buf,
uint32_t len);
* the number of bytes read on success and -1 on error. on error, use
* tsf_set_error() and friends. the caller expects read-as-much-as-
* you-can semantics, so this function should never block if some data
* is already available. */
typedef int32_t (*tsf_partial_reader_t)(void *arg,
void *buf,
uint32_t len);
struct tsf_limits {
* types calls. */
uint32_t max_types;
uint32_t max_type_size;
* together. */
uint32_t max_total_type_size;
uint32_t max_buf_size;
uint32_t depth_limit;
tsf_bool_t allow_comments;
uint8_t allow_type_kind[32];
uint32_t max_array_length;
uint32_t max_struct_size;
uint32_t max_choice_size;
uint32_t max_string_size;
};
typedef struct tsf_limits tsf_limits_t;
struct tsf_serial_in_man;
struct tsf_serial_out_man;
typedef struct tsf_serial_in_man tsf_serial_in_man_t;
typedef struct tsf_serial_out_man tsf_serial_out_man_t;
* in. */
typedef void (*tsf_type_cback_t)(tsf_serial_in_man_t *in_man,
tsf_type_t *type,
void *arg);
typedef uint32_t tsf_serial_in_man_state_t;
* and fires a TSF_E_NOT_ALLOWED error when the limit reaches 0. name
* should be a short (preferrably one-word) description of what you're
* reading; it'll be used for the error message. */
typedef struct {
tsf_reader_t reader;
void *arg;
uint32_t limit;
const char *name;
} tsf_size_aware_rdr_t;
typedef struct {
uint8_t *base;
uint8_t *cur;
uint8_t *end;
} tsf_resizable_buffer_t;
typedef struct {
uint8_t *cur,
*end;
} tsf_light_buffer_t;
typedef struct {
tsf_reader_t reader;
void *arg;
} tsf_comparing_writer_t;
struct tsf_sha1_wtr;
typedef struct tsf_sha1_wtr tsf_sha1_wtr_t;
struct tsf_buf_rdr;
struct tsf_buf_wtr;
typedef struct tsf_buf_rdr tsf_buf_rdr_t;
typedef struct tsf_buf_wtr tsf_buf_wtr_t;
struct tsf_zip_wtr_attr {
tsf_zip_mode_t mode;
uint32_t buf_size;
union {
struct {
tsf_bool_t advanced_init;
int level;
int method;
int windowBits;
int memLevel;
int strategy;
int reserved1;
int reserved2;
int reserved3;
} z;
struct {
int blockSize100k;
int verbosity;
int workFactor;
int reserved1;
int reserved2;
int reserved3;
} b;
} u;
};
struct tsf_zip_rdr_attr {
struct {
tsf_bool_t allow;
uint32_t buf_size;
tsf_bool_t advanced_init;
int windowBits;
int reserved1;
int reserved2;
int reserved3;
} z;
struct {
tsf_bool_t allow;
uint32_t buf_size;
int verbosity;
int small;
int reserved1;
int reserved2;
int reserved3;
} b;
};
typedef struct tsf_zip_wtr_attr tsf_zip_wtr_attr_t;
typedef struct tsf_zip_rdr_attr tsf_zip_rdr_attr_t;
struct tsf_zip_rdr;
struct tsf_zip_wtr;
typedef struct tsf_zip_rdr tsf_zip_rdr_t;
typedef struct tsf_zip_wtr tsf_zip_wtr_t;
struct tsf_adpt_rdr;
typedef struct tsf_adpt_rdr tsf_adpt_rdr_t;
* not mean that you can edit them! treat this as an opaque! also note
* that the state is effectively a pointer, so this mark is undefined if
* serialized... so you cannot use these things to build an external
* index. sorry. */
struct tsf_stream_file_mark {
tsf_off_t offset;
tsf_serial_in_man_state_t state;
};
typedef struct tsf_stream_file_mark tsf_stream_file_mark_t;
struct tsf_stream_file_input;
struct tsf_stream_file_output;
typedef struct tsf_stream_file_input tsf_stream_file_input_t;
typedef struct tsf_stream_file_output tsf_stream_file_output_t;
enum tsf_fsdb_kind {
TSF_FSDB_LOCAL,
TSF_FSDB_REMOTE
};
typedef enum tsf_fsdb_kind tsf_fsdb_kind_t;
struct tsf_fsdk_connection;
typedef struct tsf_fsdb_connection tsf_fsdb_connection_t;
struct tsf_fsdb;
typedef struct tsf_fsdb tsf_fsdb_t;
struct tsf_fsdb_in;
struct tsf_fsdb_out;
typedef struct tsf_fsdb_in tsf_fsdb_in_t;
typedef struct tsf_fsdb_out tsf_fsdb_out_t;
* failed in the current thread. functions in the TSF API always tell you
* whether or not they failed, usually by returning NULL (if the function
* returns pointers), tsf_false (if the function returns tsf_bool_t), or -1
* (if the function returns some sort of integer). calls to this function
* made when no error has occurred result in undefined behavior (read:
* segfault). */
tsf_error_t tsf_get_error_code(void);
* returned here is truly a constant, so you can safely refer to it
* indefinitely. note that if you want a more descriptive message for an
* error that just occurred, use tsf_get_error(). tsf_get_error() will
* almost always return a string that contains more information than using
* tsf_get_message_for_error_code(tsf_get_error_code()). note that this
* function does not check if code is a valid TSF error code; if it isn't,
* bad things will happen. */
const char* tsf_get_message_for_error_code(tsf_error_t code);
* value is undefined if the last function that failed did not fail due to
* a system error. */
int tsf_get_system_errno(void);
* value is undefined if the last function that failed did not fail due to
* a ZLib error. */
int tsf_get_zlib_error_code(void);
* value is undefined if the last function that failed did not fail due to
* a ZLib error. (NOTE: if a ZLib error actually did happen, this will
* not be NULL.)*/
const char* tsf_get_zlib_error_msg(void);
* value is undefined if the last function that failed did not fail due to
* a libbzip2 error. */
int tsf_get_libbzip2_error_code(void);
* return value is undefined if the last function that failed did not fail
* due to a libbzip2 error.*/
const char* tsf_get_libbzip2_error_msg(void);
* TSF_E_DEATH_BY_SIGNAL). the return value is undefined if the last
* function that failed did not fail due to TSF_E_DEATH_BY_SIGNAL. */
int tsf_get_deadly_signal(void);
* is not owned by you; it is only valid until the next call to
* any tsf function other than tsf_get_error_code(), tsf_get_error(),
* and the other error-getting functions above. (If the library is
* compiled with thread-safety then the previous statement refers to
* the next call by the same thread, rather than the next call
* globally.) calls to this function made when no error has
* occurred (within this thread) result in undefined behavior
* (quite possibly and very likely a segfault inside tsf_get_error()). */
const char* tsf_get_error(void);
* be the prefix of what tsf_get_error() returns. */
#define tsf_get_error_prefix() \
(tsf_get_message_for_error_code(tsf_get_error_code()))
* for errno, this is strerror(errno); , and so on. this will be NULL for
* errors in which this does not apply. if the error is set using the
* ordinary functions in this header file, this string will fall somewhere
* in the string returned by tsf_get_error() - but to be safe you should
* not rely on this fact. */
const char* tsf_get_error_infix(void);
* NULL if the user did not supply anything. if non-null, this will
* always be the suffix of what tsf_get_error() returns. */
const char* tsf_get_error_suffix(void);
* the only error string is the one that comes with the given error
* code. */
void tsf_set_error(tsf_error_t code,
const char *format,
...);
* error message contains the string "System error" and the strerror
* for the given errno. if format is non-NULL, then your text
* gets appended at the end of that. */
void tsf_set_specific_errno(int cur_errno,
const char *format,...);
* tsf_set_specific_errno() except that the global errno is used
* instead of the given errno. */
void tsf_set_errno(const char *format,...);
void tsf_set_deadly_signal(int deadly_signal,
const char *format,...);
* error message contains the string "ZLib error" and the error message
* you provide. If the format is not NULL, the text specified by the
* format is appended to that.
*
* Note that if ZLib support is not compiled in, this function will
* mean an immediate abort. */
void tsf_set_zlib_error(int error_code,
const char *error_msg,
const char *format,
...);
* error message contains the string "libbzip2 error" and an error message
* that is appropriate to the error code. If the format is not NULL, the
* text specified by the format is appended to that.
*
* Note that if libbzip2 support is not compiled in, this function will
* mean an immediate abort. */
void tsf_set_libbzip2_error(int error_code,
const char *format,
...);
const char* tsf_version(void);
int tsf_version_major(void);
int tsf_version_minor(void);
int tsf_version_patch(void);
tsf_limits_t* tsf_limits_create(void);
void tsf_limits_destroy(tsf_limits_t *limits);
* counts as error propagation. */
tsf_limits_t* tsf_limits_clone(tsf_limits_t *limits);
static TSF_inline
void tsf_limits_set_allow_type_kind(tsf_limits_t *limits,
tsf_type_kind_t kind_code) {
limits->allow_type_kind[kind_code>>3]|=(1<<(kind_code&7));
}
static TSF_inline
void tsf_limits_reset_allow_type_kind(tsf_limits_t *limits,
tsf_type_kind_t kind_code) {
limits->allow_type_kind[kind_code>>3]&=~(1<<(kind_code&7));
}
* returns tsf_true if limits is NULL. */
static TSF_inline
tsf_bool_t tsf_limits_is_type_kind_allowed(tsf_limits_t *limits,
tsf_type_kind_t kind_code) {
if (limits==NULL) {
return tsf_true;
}
return (limits->allow_type_kind[kind_code>>3]&(1<<(kind_code&7)))
?tsf_true:tsf_false;
}
static TSF_inline
const char* tsf_type_kind_tsf_name(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return "TSF_TK_INT8";
case TSF_TK_UINT8: return "TSF_TK_UINT8";
case TSF_TK_INT16: return "TSF_TK_INT16";
case TSF_TK_UINT16: return "TSF_TK_UINT16";
case TSF_TK_INT32: return "TSF_TK_INT32";
case TSF_TK_UINT32: return "TSF_TK_UINT32";
case TSF_TK_INT64: return "TSF_TK_INT64";
case TSF_TK_UINT64: return "TSF_TK_UINT64";
case TSF_TK_INTEGER: return "TSF_TK_INTEGER";
case TSF_TK_LONG: return "TSF_TK_LONG";
case TSF_TK_FLOAT: return "TSF_TK_FLOAT";
case TSF_TK_DOUBLE: return "TSF_TK_DOUBLE";
case TSF_TK_ARRAY: return "TSF_TK_ARRAY";
case TSF_TK_STRUCT: return "TSF_TK_STRUCT";
case TSF_TK_BIT: return "TSF_TK_BIT";
case TSF_TK_CHOICE: return "TSF_TK_CHOICE";
case TSF_TK_VOID: return "TSF_TK_VOID";
case TSF_TK_STRING: return "TSF_TK_STRING";
case TSF_TK_ANY: return "TSF_TK_ANY";
default: return "unknown";
}
}
static TSF_inline
tsf_bool_t tsf_type_kind_is_primitive(tsf_type_kind_t kind_code) {
return kind_code>=TSF_TK_INT8 && kind_code<=TSF_TK_DOUBLE;
}
* is the native size of the type, and for everything but TSF_TK_INTEGER
* and TSF_TK_LONG, it's also the encoded size. */
static TSF_inline
uint32_t tsf_primitive_type_kind_size_of(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return 1;
case TSF_TK_UINT8: return 1;
case TSF_TK_INT16: return 2;
case TSF_TK_UINT16: return 2;
case TSF_TK_INT32: return 4;
case TSF_TK_UINT32: return 4;
case TSF_TK_INTEGER: return 4;
case TSF_TK_INT64: return 8;
case TSF_TK_UINT64: return 8;
case TSF_TK_LONG: return 8;
case TSF_TK_FLOAT: return 4;
case TSF_TK_DOUBLE: return 8;
default: return 0;
}
}
static TSF_inline
int32_t tsf_primitive_type_kind_lower_bound(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return -1;
case TSF_TK_UINT8: return 0;
case TSF_TK_INT16: return -3;
case TSF_TK_UINT16: return 0;
case TSF_TK_INT32: return -5;
case TSF_TK_INTEGER: return -5;
case TSF_TK_UINT32: return 0;
case TSF_TK_INT64: return -7;
case TSF_TK_UINT64: return 0;
case TSF_TK_LONG: return -7;
case TSF_TK_FLOAT: return -9;
case TSF_TK_DOUBLE: return -10;
default: return 0;
}
}
static TSF_inline
int32_t tsf_primitive_type_kind_upper_bound(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return 1;
case TSF_TK_UINT8: return 2;
case TSF_TK_INT16: return 3;
case TSF_TK_UINT16: return 4;
case TSF_TK_INT32: return 5;
case TSF_TK_INTEGER: return 5;
case TSF_TK_UINT32: return 6;
case TSF_TK_INT64: return 7;
case TSF_TK_UINT64: return 8;
case TSF_TK_LONG: return 8;
case TSF_TK_FLOAT: return 9;
case TSF_TK_DOUBLE: return 10;
default: return 0;
}
}
static TSF_inline
int32_t tsf_primitive_type_kind_precision(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return 8;
case TSF_TK_UINT8: return 8;
case TSF_TK_INT16: return 16;
case TSF_TK_UINT16: return 16;
case TSF_TK_INT32: return 32;
case TSF_TK_UINT32: return 32;
case TSF_TK_INTEGER: return 32;
case TSF_TK_INT64: return 64;
case TSF_TK_UINT64: return 64;
case TSF_TK_LONG: return 64;
case TSF_TK_FLOAT: return 23;
case TSF_TK_DOUBLE: return 52;
default: return 0;
}
}
static TSF_inline
tsf_bool_t tsf_primitive_type_kind_is_float(tsf_type_kind_t kind_code) {
return kind_code==TSF_TK_FLOAT || kind_code==TSF_TK_DOUBLE;
}
#define tsf_type_kind_is_float(kind_code) \
(tsf_primitive_type_kind_is_float(kind_code))
static TSF_inline
tsf_bool_t tsf_primitive_type_kind_is_int(tsf_type_kind_t kind_code) {
return tsf_type_kind_is_primitive(kind_code) &&
!tsf_type_kind_is_float(kind_code);
}
#define tsf_type_kind_is_int(kind_code) \
(tsf_primitive_type_kind_is_int(kind_code))
static TSF_inline
tsf_bool_t tsf_primitive_type_kind_is_signed(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8:
case TSF_TK_INT16:
case TSF_TK_INT32:
case TSF_TK_INT64:
case TSF_TK_INTEGER:
case TSF_TK_LONG: return tsf_true;
default: return tsf_primitive_type_kind_is_float(kind_code);
}
}
#define tsf_type_kind_is_signed(kind_code) \
(tsf_primitive_type_kind_is_signed(kind_code))
* C type. */
static TSF_inline
const char* tsf_primitive_type_kind_c_name(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return "int8_t";
case TSF_TK_UINT8: return "uint8_t";
case TSF_TK_INT16: return "int16_t";
case TSF_TK_UINT16: return "uint16_t";
case TSF_TK_INT32: return "int32_t";
case TSF_TK_UINT32: return "uint32_t";
case TSF_TK_INT64: return "int64_t";
case TSF_TK_UINT64: return "uint64_t";
case TSF_TK_INTEGER: return "tsf_integer_t";
case TSF_TK_LONG: return "tsf_long_t";
case TSF_TK_FLOAT: return "float";
case TSF_TK_DOUBLE: return "double";
default: return "unknown";
}
}
* using lower case. */
static TSF_inline
const char* tsf_primitive_type_kind_lc_name(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return "int8";
case TSF_TK_UINT8: return "uint8";
case TSF_TK_INT16: return "int16";
case TSF_TK_UINT16: return "uint16";
case TSF_TK_INT32: return "int32";
case TSF_TK_UINT32: return "uint32";
case TSF_TK_INT64: return "int64";
case TSF_TK_UINT64: return "uint64";
case TSF_TK_INTEGER: return "integer";
case TSF_TK_LONG: return "long";
case TSF_TK_FLOAT: return "float";
case TSF_TK_DOUBLE: return "double";
default: return "unknown";
}
}
static TSF_inline
const char* tsf_type_kind_lc_name(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_ARRAY: return "array";
case TSF_TK_STRUCT: return "struct";
case TSF_TK_BIT: return "bit";
case TSF_TK_CHOICE: return "choice";
case TSF_TK_VOID: return "void";
case TSF_TK_STRING: return "string";
case TSF_TK_ANY: return "any";
default: return tsf_primitive_type_kind_lc_name(kind_code);
}
}
* we use for it. */
static TSF_inline
const char* tsf_primitive_type_kind_nh_name(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_INT8: return "c";
case TSF_TK_UINT8: return "c";
case TSF_TK_INT16: return "s";
case TSF_TK_UINT16: return "s";
case TSF_TK_INT32: return "l";
case TSF_TK_UINT32: return "l";
case TSF_TK_INT64: return "ll";
case TSF_TK_UINT64: return "ll";
case TSF_TK_INTEGER: return "l";
case TSF_TK_LONG: return "ll";
case TSF_TK_FLOAT: return "f";
case TSF_TK_DOUBLE: return "d";
default: return "unknown";
}
}
* if the domain of the first is contained in the domain of the second.
* if you wish to assign one primitive to another, then to avoid
* a loss of significant or an overflow, you must ensure that the
* source is instance of the destination. */
tsf_bool_t tsf_primitive_type_kind_instanceof(tsf_type_kind_t one,
tsf_type_kind_t two);
tsf_type_kind_t tsf_primitive_type_kind_for_spec(int32_t lower_bound,
int32_t upper_bound,
int32_t precision);
* a common subtype does not exist. */
tsf_type_kind_t tsf_primitive_type_kind_mix(tsf_type_kind_t one,
tsf_type_kind_t two);
static TSF_inline
tsf_bool_t tsf_type_kind_is_container(tsf_type_kind_t kind_code) {
switch (kind_code) {
case TSF_TK_ARRAY:
case TSF_TK_STRUCT:
case TSF_TK_CHOICE: return tsf_true;
default: return tsf_false;
}
}
static TSF_inline
tsf_bool_t tsf_type_kind_is_commentable(tsf_type_kind_t kind_code) {
return tsf_type_kind_is_container(kind_code);
}
* directly.) */
tsf_type_table_t* tsf_type_table_create(void);
tsf_bool_t tsf_type_table_copy(tsf_type_table_t *dest,
tsf_type_table_t *src);
void tsf_type_table_destroy(tsf_type_table_t *tt);
tsf_bool_t tsf_type_table_write(tsf_type_table_t *tt,
tsf_writer_t writer,
void *arg);
tsf_bool_t tsf_type_table_append(tsf_type_table_t *tt,
const char *name,
tsf_type_t *type);
* indexing of the type table if this isn't the last element.
* the only error that this could report is TSF_E_ELE_NOT_FOUND
* if the element wasn't in the table. */
tsf_bool_t tsf_type_table_remove(tsf_type_table_t *tt,
const char *name);
tsf_named_type_t* tsf_type_table_find_by_name(tsf_type_table_t *tt,
const char *name);
tsf_named_type_t* tsf_type_table_find_by_index(tsf_type_table_t *tt,
uint32_t index);
uint32_t tsf_type_table_get_num_elements(tsf_type_table_t *tt);
* the sum of the hash codes of the constituent tsf_named_type_t objects.
* hence, you can always determine what the hash code is after an
* apppend operation. */
int tsf_type_table_get_hash(tsf_type_table_t *tt);
tsf_bool_t tsf_type_table_contains_dynamic(tsf_type_table_t *tt);
tsf_bool_t tsf_type_table_compare(tsf_type_table_t *a,
tsf_type_table_t *b);
tsf_type_in_map_t* tsf_type_in_map_create(void);
tsf_type_in_map_t* tsf_type_in_map_create_in(void *region);
* be modified. */
tsf_type_in_map_t* tsf_type_in_map_get_empty_singleton(void);
tsf_type_in_map_t* tsf_type_in_map_clone(tsf_type_in_map_t *types);
tsf_type_in_map_t* tsf_type_in_map_clone_in(tsf_type_in_map_t *types,
void *region);
* empty singleton. cannot be used on region-allocated tables. */
void tsf_type_in_map_destroy(tsf_type_in_map_t *types);
* function serves as a hint and so does not have any guaranteed effect.
* as such, success in this function should not be taken to mean that
* the subsequent append operations are guaranteed to succeed and
* failure in this operation should not be taken to mean that any
* number of subsequent appends should fail.
*
* (In other words, the return value can be safely ignored. It is there
* to aid in debugging only.) */
tsf_bool_t tsf_type_in_map_prepare(tsf_type_in_map_t *types,
uint32_t num);
* types prior to the append. */
tsf_bool_t tsf_type_in_map_append(tsf_type_in_map_t *types,
tsf_type_t *type);
uint32_t tsf_type_in_map_get_num_types(tsf_type_in_map_t *types);
tsf_type_t* tsf_type_in_map_get_type(tsf_type_in_map_t *types,
uint32_t index);
* unpredictably horrible things will happen if the new size is
* greater than the current size. */
void tsf_type_in_map_truncate(tsf_type_in_map_t *types,
uint32_t new_size);
* have the same number of types, and for each index, of the types
* at that index are the same according to tsf_type_compare(). */
tsf_bool_t tsf_type_in_map_compare(tsf_type_in_map_t *a,
tsf_type_in_map_t *b);
tsf_type_out_map_t* tsf_type_out_map_create(void);
void tsf_type_out_map_destroy(tsf_type_out_map_t *type_map);
* returned if it is not found. */
tsf_bool_t tsf_type_out_map_find_type_code(tsf_type_out_map_t *type_map,
tsf_type_t *type,
uint32_t *type_code);
* a type code had to be created AND that creation failed. */
tsf_bool_t tsf_type_out_map_get_type_code(tsf_type_out_map_t *type_map,
tsf_type_t *type,
uint32_t *type_code,
tsf_bool_t *created);
tsf_type_in_map_t* tsf_type_in_map_from_type_out_map(
tsf_type_out_map_t *type_map);
* creates the type in thingy in the provided region. */
tsf_type_in_map_t* tsf_type_in_map_from_type_out_map_in(
tsf_type_out_map_t *type_map,
void *region);
tsf_ra_type_man_t* tsf_ra_type_man_create(void);
tsf_ra_type_man_t* tsf_ra_type_man_read(tsf_reader_t reader,
void *arg);
void tsf_ra_type_man_destroy(tsf_ra_type_man_t *man);
tsf_bool_t tsf_ra_type_man_write(tsf_ra_type_man_t *man,
tsf_writer_t writer,
void *arg);
that the type is not already in the type manager. */
tsf_bool_t tsf_ra_type_man_insert(tsf_ra_type_man_t *man,
tsf_type_t *type,
uint32_t type_code,
uint64_t ref_count);
that the type is in the type manager. */
void tsf_ra_type_man_remove(tsf_ra_type_man_t *man,
tsf_type_t *type);
not found, NULL will be retorned and an error code will be set. */
tsf_type_t* tsf_ra_type_man_find(tsf_ra_type_man_t *man,
uint32_t type_code);
tsf_bool_t tsf_ra_type_man_has_type(tsf_ra_type_man_t *man,
tsf_type_t *type);
the type manager has the type. */
uint32_t tsf_ra_type_man_get_type_code(tsf_ra_type_man_t *man,
tsf_type_t *type);
is not in the type manager, it is added to the type manager,
assigned a type code, and given a reference count of 1. */
tsf_bool_t tsf_ra_type_man_get_reference(tsf_ra_type_man_t *man,
tsf_type_t *type);
count drops to 0, the type is removed. */
void tsf_ra_type_man_remove_reference(tsf_ra_type_man_t *man,
tsf_type_t *type);
uint32_t tsf_ra_type_man_num_types(tsf_ra_type_man_t *man);
the given buffer. */
tsf_bool_t tsf_ra_type_man_has_buf_types(tsf_ra_type_man_t *man,
tsf_buffer_t *buf);
creates any types that don't exist. */
tsf_bool_t tsf_ra_type_man_get_buf_references(tsf_ra_type_man_t *man,
tsf_buffer_t *buf);
void tsf_ra_type_man_remove_buf_references(tsf_ra_type_man_t *man,
tsf_buffer_t *buf);
uint32_t tsf_ra_type_man_get_type_code_free_list_size(
tsf_ra_type_man_t *man);
* if you want to create a type with kind ccode TSF_TK_ARRAY, use
* tsf_type_create_array().
*
* this can only fail due to memory allocation failure or if the kind_code
* is invalid. */
tsf_type_t* tsf_type_create(tsf_type_kind_t kind_code);
*
* this can only fail due to memory allocation failure or if element_type is
* NULL, in which case it returns without setting error. */
tsf_type_t* tsf_type_create_array(tsf_type_t *element_type);
* tsf_type_create() in combination with tsf_struct_type_append() to do
* what this method does. also, you can safely use
* tsf_struct_type_append() on the type returned from this method.
*
* the way you would actually use this is to pass struct element names
* paired with types. for example:
*
* tsf_type_t *my_type =
* tsf_type_create_struct("x",
* tsf_type_create(TSF_TK_FLOAT),
* "y",
* tsf_type_create(TSF_TK_FLOAT),
* NULL);
*
* note that you must pass NULL after the last pair. otherwise you'll
* get random crashes and stuff.
*
* the types passed to this function become owned by the function
* regardless of success or error. */
tsf_type_t* tsf_type_create_struct(const char *first_name,
...);
* from your own subrutines that use variable args. */
tsf_type_t* tsf_type_create_structv(const char *first_name,
va_list lst);
* tsf_type_create() in combination with tsf_choice_type_append() to do
* what this method does. also, you can safely use
* tsf_choice_type_append() on the type returned from this method.
*
* the way you would actually use this is to pass struct element names
* paired with types. for example:
*
* tsf_type_t *my_type =
* tsf_type_create_choice("x",
* tsf_type_create(TSF_TK_FLOAT),
* "y",
* tsf_type_create(TSF_TK_FLOAT),
* NULL);
*
* note that you must pass NULL after the last pair. otherwise you'll
* get random crashes and stuff.
*
* the types passed to this function become owned by the function
* regardless of success or error. */
tsf_type_t* tsf_type_create_choice(const char *first_name,
...);
* from your own subrutines that use variable args. */
tsf_type_t* tsf_type_create_choicev(const char *first_name,
va_list lst);
tsf_type_t* tsf_type_read(tsf_reader_t reader,
void *arg,
tsf_limits_t *limits);
tsf_bool_t tsf_type_write(tsf_type_t *type,
tsf_writer_t writer,
void *arg);
* separately destroyed. so, if you wish to retain the type after a
* call to a function that might destroy it, call this first. this
* will only return NULL if the type you pass it is NULL, for the
* purpose of error propagation. this will never create an error. */
tsf_type_t* tsf_type_dup(tsf_type_t *type);
void tsf_type_destroy(tsf_type_t *type);
* fail. note further that the size is lazily computed, so the first time
* you call this, it will be expensive, but it will become cheap for all
* subsequent calls. */
uint32_t tsf_type_get_byte_size(tsf_type_t *type);
* probably at least as expensive as writing or reading a type. tsf_true
* is returned if the type is OK. if tsf_false is returned,
* TSF_E_NOT_ALLOWED is set. if limits is NULL, all types should
* verify */
tsf_bool_t tsf_type_verify(tsf_type_t *type,
tsf_limits_t *limits);
* may benefit from memoizing the type first; then you can use a pointer
* hash. */
int tsf_type_get_hash(tsf_type_t *type);
* for two types for ehich tsf_type_compare returns true should be
* identical, i.e. point to the same tsf_type object. this does not
* consume the type you pass it. the returned type is not owned by you
* and is only guaranteed to stay alive as long as you don't destroy
* the type you passed. therefore you might want to do:
*
* memo_type = tsf_type_dup(tsf_type_memo(type));
*
* if you want to be safe. if you want to relinquish ownership of the
* original type and have ownership of the memo, you probably want:
*
* memo_type = tsf_type_dup(tsf_type_memo(type));
* tsf_type_destroy(type);
*
* note that it's possible for tsf_type_memo() to simply return the
* type it was passed, if that is the only extant type that looks like
* that. also note that memoization ignores the native mapping, so
* using the above memo-and-relinquish dance is not useful for types
* that have native mapping. however, it's still useful to memoize such
* types if you want to speed up hashing and comparing. */
tsf_type_t* tsf_type_memo(tsf_type_t *type);
it) */
tsf_bool_t tsf_type_is_dynamic(tsf_type_t *type);
* are still your responsibility after the call. returns tsf_true
* if the types are equal, tsf_false otherwise. */
tsf_bool_t tsf_type_compare(tsf_type_t *a, tsf_type_t *b);
* the instanceof relationship is defined in a big comment up above
* the definition of the tsf_type_kind enumeration. */
tsf_bool_t tsf_type_instanceof(tsf_type_t *one,
tsf_type_t *two);
tsf_type_kind_t tsf_type_get_kind_code(tsf_type_t *type);
* it returns UINT32_MAX. */
uint32_t tsf_type_get_static_size(tsf_type_t *type);
* or if the type is not commentable. */
const char* tsf_type_get_comment(tsf_type_t *type);
tsf_bool_t tsf_type_has_comment(tsf_type_t *type);
* type is not commentable. */
tsf_bool_t tsf_type_set_comment(tsf_type_t **type,
const char *comment);
* the type is not commentable. */
const char* tsf_type_get_name(tsf_type_t *type);
tsf_bool_t tsf_type_has_name(tsf_type_t *type);
* type is not commentable. */
tsf_bool_t tsf_type_set_name(tsf_type_t **type,
const char *name);
tsf_bool_t tsf_type_has_version(tsf_type_t *type);
uint32_t tsf_type_get_raw_version(tsf_type_t *type);
uint16_t tsf_type_get_major_version(tsf_type_t *type);
uint8_t tsf_type_get_minor_version(tsf_type_t *type);
uint8_t tsf_type_get_patch_version(tsf_type_t *type);
* type is not commentable. */
tsf_bool_t tsf_type_set_raw_version(tsf_type_t **type,
uint32_t version);
* type is not commentable. */
tsf_bool_t tsf_type_set_version(tsf_type_t **type,
uint16_t major,
uint8_t minor,
uint8_t patch);
* object is not owned by you; it is owned by the array type. */
tsf_type_t* tsf_array_type_get_element_type(tsf_type_t *type);
* does not become owned by the function; it is still your
* responsibility to free it. note that the string cannot
* exceed TSF_STR_SIZE; if it does, an error will be returned.
* this will propagate errors on the *ele_type.
*
* this only fails if memory allocation fails, if the name string
* is too long, or ele_type is NULL. */
tsf_bool_t tsf_struct_type_append(tsf_type_t **type,
const char *name,
tsf_type_t *ele_type);
tsf_bool_t tsf_struct_type_set_optional(tsf_type_t **type,
const char *name,
tsf_bool_t optional);
tsf_bool_t tsf_struct_type_set_comment(tsf_type_t **type,
const char *name,
const char *comment);
* fields. */
tsf_bool_t tsf_struct_type_remove(tsf_type_t **type,
const char *name);
* fast, as it uses a hashtable. */
tsf_type_t* tsf_struct_type_find(tsf_type_t *type,
const char *name);
* element contains more info. this search should be fast,
* as it uses a hashtable. */
tsf_named_type_t* tsf_struct_type_find_node(tsf_type_t *type,
const char *name);
uint32_t tsf_struct_type_get_num_elements(tsf_type_t *type);
tsf_named_type_t *tsf_struct_type_get_element(tsf_type_t *type,
uint32_t index);
const char* tsf_struct_type_get_element_name(tsf_type_t *type,
uint32_t index);
tsf_type_t* tsf_struct_type_get_element_type(tsf_type_t *type,
uint32_t index);
* does not become owned by the function; it is still your
* responsibility to free it. note that the string cannot
* exceed TSF_STR_SIZE; if it does, an error will be returned.
* this will propagate errors on the *ele_type. */
tsf_bool_t tsf_choice_type_append(tsf_type_t **type,
const char *name,
tsf_type_t *ele_type);
tsf_bool_t tsf_choice_type_set_comment(tsf_type_t **type,
const char *name,
const char *comment);
* fast, as it uses a hashtable. */
tsf_type_t* tsf_choice_type_find(tsf_type_t *type,
const char *name);
* element contains more info. this search should be fast,
* as it uses a hashtable. */
tsf_named_type_t* tsf_choice_type_find_node(tsf_type_t *type,
const char *name);
uint32_t tsf_choice_type_get_num_elements(tsf_type_t *type);
tsf_named_type_t* tsf_choice_type_get_element(tsf_type_t *type,
uint32_t index);
const char* tsf_choice_type_get_element_name(tsf_type_t *type,
uint32_t index);
tsf_type_t* tsf_choice_type_get_element_type(tsf_type_t *type,
uint32_t index);
tsf_bool_t tsf_choice_type_has_non_void(tsf_type_t *type);
* -> the latter choice type has at least as many elements as the
* first, and
* -> for each of the elements in the first choice type, the element
* in the second choice type that has the same index also has the
* same name.
*
* note that the element types do not have to match for this
* predicate to hold. however, if you are interested in adding an
* instanceof constraint for the corresponding elements of the two
* choice types, you can do so by performing an instanceof test on
* a and b. */
tsf_bool_t tsf_choice_type_uses_same_indices(tsf_type_t *a,
tsf_type_t *b);
* failure to create this thing results in the type being destroyed.
* the has_offset field is set to false, the offset field is set to 0,
* and the comment field is set to NULL. */
tsf_named_type_t* tsf_named_type_create(const char *name,
tsf_type_t *type,
uint32_t index);
* comment if there is one. */
void tsf_named_type_destroy(tsf_named_type_t *node);
* should be treated as a constant string that you do not own. */
const char* tsf_named_type_get_name(tsf_named_type_t *node);
* of type tsf_type_t* and should be treated as constant that you
* do not own. */
tsf_type_t* tsf_named_type_get_type(tsf_named_type_t *node);
* type. */
uint32_t tsf_named_type_get_index(tsf_named_type_t *node);
tsf_bool_t tsf_named_type_get_optional(tsf_named_type_t *node);
void tsf_named_type_set_optional(tsf_named_type_t *node,
tsf_bool_t optional);
* no comment was ever set */
const char* tsf_named_type_get_comment(tsf_named_type_t *node);
tsf_bool_t tsf_named_type_has_comment(tsf_named_type_t *node);
* necessary. */
tsf_bool_t tsf_named_type_set_comment(tsf_named_type_t *node,
const char *comment);
* of type TSF_TK_STRUCT and TSF_TK_CHOICE will use the sum of these hash
* codes as part of computing their own hash code. you're guaranteed
* that tsf_type_table_table_t will use the sum of these hash codes as
* part of computing their own hash code. */
int tsf_named_type_get_hash(tsf_named_type_t *node);
* becomes owned. and, to make things more interesting, the boolean
* argument determines if the void* is owned by the buffer. if it is
* owned by the buffer, then if this function fails, the buffer will be
* freed. */
tsf_buffer_t* tsf_buffer_create(tsf_type_t *type,
tsf_type_in_map_t *types,
void *data,
uint32_t size,
tsf_bool_t keep);
* except that the buffer is created in a region. it is assumed
* that the void* data is allocated in the same region and that
* tsf_type_in_map_t* is, too. note that the tsf_bool_t argument
* is omitted since tsf_buffer_destroy() is not applicable to
* region-allocated buffers. */
tsf_buffer_t* tsf_buffer_create_in(tsf_type_t *type,
tsf_type_in_map_t *types,
void *data,
uint32_t size,
void *region);
tsf_buffer_t* tsf_buffer_get_empty_singleton(void);
* true. note that this is a deep clone, so that the actual data
* itself is also copied. this means that this operation, and any
* operations on the new buffer have no effect on the original buffer. */
tsf_buffer_t* tsf_buffer_clone(tsf_buffer_t *buf);
* tsf_buffer_clone() except for the region part. */
tsf_buffer_t* tsf_buffer_clone_in(tsf_buffer_t *buf,
void *region);
* until you call tsf_buffer_destroy on it. if the buffer was heap-
* allocated and has the keep bit set to true, this operation will be
* very fast - it will increment a count and maybe do some simple
* locking/unlocking. if the buffer was region allocated or if the
* keep bit was set to false, then this has the same cost as
* tsf_buffer_clone(). as such, you must do error checking after a
* a call to tsf_buffer_dup(). */
tsf_buffer_t* tsf_buffer_dup(tsf_buffer_t *buf);
void tsf_buffer_destroy(tsf_buffer_t *buf);
uint32_t tsf_buffer_get_size(tsf_buffer_t *buf);
const void* tsf_buffer_get_data(tsf_buffer_t *buf);
* type. this is also a bit of a trusted routine...
* if the region pointer is non-NULL, then the resulting buffer will
* be region-allocated. otherwise it will be malloc-allocated and
* you will be expected to call tsf_buffer_destroy() at some point. */
tsf_buffer_t* tsf_buffer_read_from_buf(tsf_type_in_map_t *enclosing_types,
uint8_t **cur,
uint8_t *end,
void *region);
translation table if dealing with a dynamic type. */
tsf_bool_t tsf_buffer_skip_in_buf(tsf_type_in_map_t *enclosing_types,
uint8_t **cur,
uint8_t *end);
* another buffer. */
uint32_t tsf_buffer_calc_size(tsf_buffer_t *buf);
tsf_bool_t tsf_buffer_write_to_buf(tsf_buffer_t *buf,
tsf_type_out_map_t *type_map,
uint8_t **target);
* optimized operation, but it should be fine if the size of the buffer's
* data is large compared to the size of the type. */
tsf_bool_t tsf_buffer_write_whole(tsf_buffer_t *buf,
tsf_writer_t writer,
void *arg);
tsf_buffer_t* tsf_buffer_read_whole(tsf_reader_t reader,
void *arg,
tsf_limits_t *limits);
* an optimized operation. note that the result is placed in the
* uint32_t* buffer, which must be big enough to hold 5 uint32_t's. */
tsf_bool_t tsf_buffer_calc_sha1(tsf_buffer_t *buf,
uint32_t *result);
* the same payload bytes, if their types are the same according to
* tsf_type_compare(), and if their type tables are the same according
* to tsf_type_in_map_compare(). */
tsf_bool_t tsf_buffer_compare(tsf_buffer_t *a,
tsf_buffer_t *b);
tsf_type_t* tsf_buffer_get_type(tsf_buffer_t *buf);
tsf_bool_t tsf_buffer_instanceof(tsf_buffer_t *buf,
tsf_type_t *type);
tsf_type_in_map_t* tsf_buffer_get_shared_types(tsf_buffer_t *buf);
static TSF_inline
size_t tsf_sizeof_bitvector(uint32_t num_bits) {
return (num_bits + 7) >> 3;
}
static TSF_inline
void tsf_bitvector_set(tsf_native_bitvector_t *bitvector,
size_t bit_index,
tsf_bool_t value) {
uint8_t *byte = bitvector->bits + (bit_index >> 3);
uint8_t bit_mask = 1 << (bit_index & 7);
if (value)
*byte |= bit_mask;
else
*byte &= ~bit_mask;
}
static TSF_inline
tsf_bool_t tsf_bitvector_get(tsf_native_bitvector_t *bitvector,
size_t bit_index) {
uint8_t *byte = bitvector->bits + (bit_index >> 3);
uint8_t bit_mask = 1 << (bit_index & 7);
return (*byte & bit_mask) != 0;
}
* more type headers to precede data. instances of this type are not
* thread-safe; if you want to use one from multiple threads then you need
* to use locking around all calls. */
tsf_serial_in_man_t* tsf_serial_in_man_create(tsf_reader_t reader,
void *arg,
tsf_limits_t *limits);
void tsf_serial_in_man_destroy(tsf_serial_in_man_t *in_man);
* if this command is not what is found in the input stream, an error is
* reported. provided that a TSF_SP_C_RESET_TYPES command is in fact
* found, the type mapping will be reset.
*
* will set error to TSF_E_UNEXPECTED_EOF if there weren't enough bytes for
* a TSF_SP_C_RESET_TYPES command.
*
* will set error to TSF_E_PARSE_ERROR if the bytes read were not the
* currect ones (effectively, this is complaining of a bad magic number).*/
tsf_bool_t tsf_serial_in_man_read_reset_types(tsf_serial_in_man_t *in_man);
* it. returns true if there was a reset types command and false on
* error. returns the same errors as tsf_serial_in_man_read_reset_types()
* unless something really weird happens. */
tsf_bool_t tsf_serial_in_man_read_reset_types_from_fd(int fd);
* tsf_serial_in_man_read_reset_types_from_fd on it. */
tsf_bool_t tsf_serial_in_man_read_reset_types_from_file(
const char *filename);
* encounters a new type. */
tsf_bool_t tsf_serial_in_man_register_type_cback(
tsf_serial_in_man_t *in_man,
tsf_type_cback_t cback,
void *arg);
* and void* argument. */
uint32_t tsf_serial_in_man_unregister_type_cback(
tsf_serial_in_man_t *in_man,
tsf_type_cback_t cback,
void *arg);
tsf_buffer_t* tsf_serial_in_man_read(tsf_serial_in_man_t *in_man);
* access files and you wish to seek back to the position you're in now,
* you also need to save the state of the input manager and restore it
* right after the seek. */
tsf_serial_in_man_state_t tsf_serial_in_man_get_state(tsf_serial_in_man_t *in_man);
* that the serial input manager is being used to read. */
void tsf_serial_in_man_set_state(tsf_serial_in_man_t *in_man,
tsf_serial_in_man_state_t state);
* you want to use one from multiple threads then you need to lock around
* calls. */
tsf_serial_out_man_t* tsf_serial_out_man_create(tsf_writer_t writer,
void *arg);
void tsf_serial_out_man_destroy(tsf_serial_out_man_t *out_man);
tsf_bool_t tsf_serial_out_man_reset_types(tsf_serial_out_man_t *out_man);
* propagation on *buf. */
tsf_bool_t tsf_serial_out_man_write(tsf_serial_out_man_t *out_man,
tsf_buffer_t *buf);
* gets dupped for the returned structure. this will
* do error propagation on *type.
*
* Note that this function should never be used to create
* primitives, bits, voids, or strings. */
tsf_reflect_t* tsf_reflect_create(tsf_type_t *type);
tsf_reflect_t* tsf_reflect_create_int8_t(int8_t value);
tsf_reflect_t* tsf_reflect_create_uint8_t(uint8_t value);
tsf_reflect_t* tsf_reflect_create_int16_t(int16_t value);
tsf_reflect_t* tsf_reflect_create_uint16_t(uint16_t value);
tsf_reflect_t* tsf_reflect_create_int32_t(int32_t value);
tsf_reflect_t* tsf_reflect_create_uint32_t(uint32_t value);
tsf_reflect_t* tsf_reflect_create_int64_t(int64_t value);
tsf_reflect_t* tsf_reflect_create_uint64_t(uint64_t value);
tsf_reflect_t* tsf_reflect_create_integer(tsf_integer_t value);
tsf_reflect_t* tsf_reflect_create_long(tsf_long_t value);
tsf_reflect_t* tsf_reflect_create_float(float value);
tsf_reflect_t* tsf_reflect_create_double(double value);
#define tsf_reflect_create_primitive(type,value) \
(tsf_reflect_create_##type(value))
tsf_reflect_t* tsf_reflect_create_bit(tsf_bool_t value);
* the void type. you'll probably only have to deal with this if
* you use the choice type for enumerations. */
tsf_reflect_t* tsf_reflect_create_void(void);
tsf_reflect_t* tsf_reflect_create_string(const char *str);
* anything. the buffer becomes owned by the reflect object,
* so that even if this creation fails, the buffer is no longer
* available to you. */
tsf_reflect_t* tsf_reflect_create_any(tsf_buffer_t *buf);
tsf_reflect_t* tsf_reflect_clone(tsf_reflect_t *data);
void tsf_reflect_destroy(tsf_reflect_t *data);
tsf_buffer_t* tsf_reflect_make_buffer(tsf_reflect_t *data);
tsf_reflect_t* tsf_reflect_from_buffer(tsf_buffer_t *buf);
tsf_type_t* tsf_reflect_get_type(tsf_reflect_t *data);
tsf_type_kind_t tsf_reflect_get_kind_code(tsf_reflect_t *data);
* *ele_data. */
tsf_bool_t tsf_struct_reflect_set_element(tsf_reflect_t *data,
const char *name,
tsf_reflect_t *ele_data);
on *ele. */
tsf_bool_t tsf_struct_reflect_set_element_by_index(tsf_reflect_t *data,
uint32_t index,
tsf_reflect_t *ele);
tsf_reflect_t* tsf_struct_reflect_get_element(tsf_reflect_t *data,
const char *name);
tsf_reflect_t* tsf_struct_reflect_get_element_by_index(tsf_reflect_t *data,
uint32_t index);
uint32_t tsf_struct_reflect_get_num_elements(tsf_reflect_t *data);
equivalent to calling tsf_choice_reflect_set_unknown(). this means
that ele_data is ignored. */
tsf_bool_t tsf_choice_reflect_set(tsf_reflect_t *data,
const char *choice,
tsf_reflect_t *ele_data);
UINT32_MAX, this is equivalent to calling
tsf_choice_reflect_set_unknown(). this means that ele_data is ignored. */
tsf_bool_t tsf_choice_reflect_set_by_index(tsf_reflect_t *data,
uint32_t index,
tsf_reflect_t *ele_data);
tsf_bool_t tsf_choice_reflect_set_unknown(tsf_reflect_t *data);
uint32_t tsf_choice_reflect_get_index(tsf_reflect_t *data);
tsf_bool_t tsf_choice_reflect_is_known(tsf_reflect_t *data);
const char* tsf_choice_reflect_get_choice(tsf_reflect_t *data);
* return NULL. */
tsf_reflect_t* tsf_choice_reflect_get_data(tsf_reflect_t *data);
* on *ele_data. */
tsf_bool_t tsf_array_reflect_append(tsf_reflect_t *data,
tsf_reflect_t *ele_data);
tsf_reflect_t* tsf_array_reflect_get_element(tsf_reflect_t *data,
uint32_t index);
uint32_t tsf_array_reflect_get_num_elements(tsf_reflect_t *data);
int8_t tsf_int8_t_reflect_get(tsf_reflect_t *data);
uint8_t tsf_uint8_t_reflect_get(tsf_reflect_t *data);
int16_t tsf_int16_t_reflect_get(tsf_reflect_t *data);
uint16_t tsf_uint16_t_reflect_get(tsf_reflect_t *data);
int32_t tsf_int32_t_reflect_get(tsf_reflect_t *data);
uint32_t tsf_uint32_t_reflect_get(tsf_reflect_t *data);
int64_t tsf_int64_t_reflect_get(tsf_reflect_t *data);
uint64_t tsf_uint64_t_reflect_get(tsf_reflect_t *data);
tsf_integer_t tsf_integer_reflect_get(tsf_reflect_t *data);
tsf_long_t tsf_long_reflect_get(tsf_reflect_t *data);
float tsf_float_reflect_get(tsf_reflect_t *data);
double tsf_double_reflect_get(tsf_reflect_t *data);
#define tsf_primitive_reflect_get(data,type) \
(tsf_##type##_reflect_get(data))
tsf_bool_t tsf_bit_reflect_get(tsf_reflect_t *data);
const char* tsf_string_reflect_get(tsf_reflect_t *data);
tsf_buffer_t* tsf_any_reflect_get_buffer(tsf_reflect_t *data);
* this does not tell you if the given type has a mapping within its
* parent type - it only tells you if the types it contains have
* mappings. hence, this always returns tsf_true for types that are not
* containers. if this function returns tsf_false, then calling any of
* the tsf_native functions on this type will result in unpredictable
* behavior (unless otherwise noted). */
tsf_bool_t tsf_native_type_has_struct_mapping(tsf_type_t *type);
* struct. this can only be called on types that have a struct
* mapping. */
size_t tsf_native_type_get_size(tsf_type_t *type);
* the given type. will return UINTm_MAX if the bound cannot be deduced. */
void tsf_native_type_get_total_size_bounds(tsf_type_t *type,
size_t *min,
size_t *max);
* size will give the 'desired' result. */
tsf_bool_t tsf_native_type_can_blit(tsf_type_t *dest_type,
tsf_type_t *src_type);
size_t tsf_native_named_type_get_offset(tsf_named_type_t *node);
* that this function is not particularly fast. however, you shouldn't
* care about the speed of this function since you should only ever
* call it once for each structure element for the lifetime of your
* program. */
tsf_bool_t tsf_native_struct_type_map(tsf_type_t **type,
const char *name,
size_t offset);
* this function is not particularly fast. */
tsf_bool_t tsf_native_struct_type_set_size(tsf_type_t **type,
size_t size);
* tsf_type_create(TSF_TK_STRUCT) and then calling
* tsf_native_struct_type_set_size(). */
tsf_type_t* tsf_native_struct_type_create(size_t size);
* tsf_struct_type_append() and then tsf_native_struct_type_map(). */
tsf_bool_t tsf_native_struct_type_append(tsf_type_t **type,
const char *name,
tsf_type_t *ele_type,
size_t offset);
* the struct are populated during parsing of copying. this is appropriate
* for initializing other fields that the user-defined struct might have. */
tsf_bool_t tsf_native_struct_type_set_constructor(tsf_type_t **type,
void (*cons)(void*));
* deallocated. for region-allocated structs, this gets added as a region
* destruction callback. */
tsf_bool_t tsf_native_struct_type_set_pre_destructor(tsf_type_t **type,
void (*pre_dest)(void*));
* destruction in tsf_destructor. setting this means that destroying the struct
* using a destructor will not call the pre_destructor. */
tsf_bool_t tsf_native_struct_type_set_destructor(tsf_type_t **type,
void (*dest)(void*));
void (*tsf_native_struct_type_get_constructor(tsf_type_t *type))(void*);
void (*tsf_native_struct_type_get_pre_destructor(tsf_type_t *type))(void*);
void (*tsf_native_struct_type_get_destructor(tsf_type_t *type))(void*);
tsf_bool_t tsf_native_choice_type_map(tsf_type_t **type,
tsf_bool_t in_place,
size_t value_offset,
size_t data_offset,
size_t size);
tsf_type_t* tsf_native_choice_type_create(tsf_bool_t in_place,
size_t value_offset,
size_t data_offset,
size_t size);
tsf_bool_t tsf_native_choice_type_is_in_place(tsf_type_t *type);
size_t tsf_native_choice_type_get_data_offset(tsf_type_t *type);
size_t tsf_native_choice_type_get_value_offset(tsf_type_t *type);
size_t tsf_native_choice_type_get_size(tsf_type_t *type);
* to use this method, since you get no guarantee that this will map to
* any of your structures. this method's main intent is to aid in the
* writing of regression tests.
*
* if do_align is tsf_true, each element will be aligned according to
* the detected native alignment (the alignment necessary for the largest
* data type, which is usually determined by either pointers or doubles).
*
* if do_align is tsf_false, no alignment guarantee is made. you have
* to be quite careful when using this option, as it might cause the
* GPC programs generated for this type to crash. */
tsf_bool_t tsf_native_type_produce_some_mapping(tsf_type_t **type,
tsf_bool_t do_align);
* that can be used to produce tsf_buffer_t objects from pointers
* to the struct. */
tsf_genrtr_t* tsf_generator_create(tsf_type_t *type);
tsf_buffer_t* tsf_generator_generate(tsf_genrtr_t *gen,
void *data);
tsf_buffer_t* tsf_generator_generate_in(tsf_genrtr_t *gen,
void *data,
void *region);
void tsf_generator_destroy(tsf_genrtr_t *gen);
* that can be used to read tsf_buffer_t objects and produce data
* that has the structure you specified in the struct mapping. */
tsf_parser_t* tsf_parser_create(tsf_type_t *type);
* in the type you gave to tsf_parser_create().
*
* stuff returned from this function can be freed using
* tsf_region_free() (see tsf_region.h). */
void* tsf_parser_parse(tsf_parser_t *parser,
tsf_buffer_t *buffer);
* in the type you gave to tsf_parser_create(). the data is
* allocated in the given region instead of having a new region
* created. */
void* tsf_parser_parse_in(tsf_parser_t *parser,
tsf_buffer_t *buffer,
void *region);
* region. you can pass NULL for the region if you want to use malloc for
* all allocations. */
tsf_bool_t tsf_parser_parse_into(tsf_parser_t *parser,
tsf_buffer_t *buffer,
void *result,
void *region);
void tsf_parser_destroy(tsf_parser_t *parser);
* measure of the parser's memory efficiency. */
uint32_t tsf_parser_num_codes(tsf_parser_t *parser);
* source is not instanceof the destination, you will get an error. */
tsf_copier_t* tsf_copier_create(tsf_type_t *dest,
tsf_type_t *src);
void tsf_copier_destroy(tsf_copier_t *copier);
* object of the destination type. the object returned can be
* freed with tsf_region_free(). */
void* tsf_copier_clone(tsf_copier_t *copier,
void *src);
* object of the destination type. the object returned will be
* allocated in the given region. */
void* tsf_copier_clone_in(tsf_copier_t *copier,
void *src,
void *region);
* also, use the provided region for allocation. note that you can pass a
* NULL region, which causes this to use malloc for allocations. */
tsf_bool_t tsf_copier_copy(tsf_copier_t *copier,
void *dest,
void *src,
void *region);
* memory used by objects of a given type, provided that the objects were
* allocated with malloc and not with a region. */
tsf_destructor_t* tsf_destructor_create(tsf_type_t *type);
void tsf_destructor_destroy(tsf_destructor_t *destructor);
void tsf_destructor_destruct(tsf_destructor_t *destructor,
void *object);
* an integer holding the file descriptor. */
tsf_bool_t tsf_fd_writer(void *arg,
const void *data,
uint32_t len);
* an integer holding the file descriptor. if an EOF happens before
* any data is ready, this function will set the TSF_E_UNEXPECTED_EOF
* error. if an EOF happens after any data is ready,
* TSF_E_ERRONEOUS_EOF will be set instead. if the EOF was expected,
* you should change the TSF_E_UNEXPECTED_EOF error to TSF_E_EOF if
* you propagate that error (see tsf_in_man.c for a good example of
* what I'm talking about). */
tsf_bool_t tsf_fd_reader(void *arg,
void *data,
uint32_t len);
* to an integer holding the file descriptor. this differs from
* tsf_fd_reader() in that complete writes are never guaranteed.
* if an EOF happens, this function will set the TSF_E_UNEXPECTED_EOF
* error. if the EOF was expected, you should change the
* TSF_E_UNEXPECTED_EOF error to TSF_E_EOF if you propagate that error
* (see tsf_in_man.c for a good example of what I'm talking about). */
int32_t tsf_fd_partial_reader(void *arg,
void *data,
uint32_t len);
tsf_bool_t tsf_full_read_of_partial(tsf_partial_reader_t reader,
void *arg,
void *data,
uint32_t len);
char* tsf_read_string(tsf_reader_t reader,
void *arg,
size_t max_size);
tsf_bool_t tsf_write_string(tsf_writer_t writer,
void *arg,
const char *str);
* the referenced uint32_t is the length. you should initialize
* the length to 0 before using this writer. note that this
* writer does not write the contents to anywhere; it only tells
* you the contents' size. */
tsf_bool_t tsf_size_calc_writer(void *arg,
const void *buf,
uint32_t len);
* amount read exceeds a limit. the error will be
* TSF_E_PARSE_ERROR. the arg should be a tsf_size_aware_rdr_t*,
* which you should initialize with the reader to delegate to,
* the arg that that reader expects, a limit, and a name. the
* name is used for generating the message for the parse error,
* if it occurs, and should be a short (preferably one word)
* description of what it is you're reading. */
tsf_bool_t tsf_size_aware_reader(void *arg,
void *buf,
uint32_t len);
* then use this buffer with the buffer-only reader. the argument is a
* uint8_t**. this function will dereference it and use it as an iterator
* as it writes. */
tsf_bool_t tsf_buffer_only_writer(void *arg,
const void *buf,
uint32_t len);
* enough room. takes a tsf_resizable_buffer_t. it's valid to start by
* memsetting the tsf_resizable_buffer_t to zero. */
tsf_bool_t tsf_resizable_buffer_writer(void *arg,
const void *buf,
uint32_t len);
tsf_bool_t tsf_buffer_only_reader(void *arg,
void *buf,
uint32_t len);
byte doesn't match. */
tsf_bool_t tsf_comparing_writer(void *arg,
const void *buf,
uint32_t len);
32-bit integer. */
tsf_bool_t tsf_hashing_writer(void *arg,
const void *buf,
uint32_t len);
tsf_sha1_wtr_t* tsf_sha1_writer_create(void);
void tsf_sha1_writer_destroy(tsf_sha1_wtr_t *sha1);
tsf_bool_t tsf_sha1_writer_write(void *arg,
const void *buf,
uint32_t len);
* this function is called you cannot write into this writer anymore.
* calling this function repeatedly will simply return the same
* result. */
uint32_t* tsf_sha1_writer_finish(tsf_sha1_wtr_t *sha1);
* the same array as tsf_sha1_writer_finish(). you should not call
* this function until after you have called tsf_sha1_writer_finish().
* in this sense, this function is somewhat redundant to
* tsf_sha1_writer_finish(), but is provided for convenience. */
uint32_t* tsf_sha1_writer_result(tsf_sha1_wtr_t *sha1);
* sum in the argument. note, the returned string is newly allocated,
* so you must free it when you're done. */
char* tsf_sha1_sum_to_str(uint32_t *sum);
* buffer size. if keep_fd is tsf_true, the file descriptor will be
* closed if: an error occurs while trying to create the buffer,
* and when the buffer is destroyed. */
tsf_buf_rdr_t* tsf_buf_reader_create(int fd,
uint32_t buf_size,
tsf_bool_t keep_fd);
void tsf_buf_reader_destroy(tsf_buf_rdr_t *buf);
tsf_bool_t tsf_buf_reader_read(void *buf,
void *data,
uint32_t len);
uint32_t tsf_buf_reader_get_remaining(tsf_buf_rdr_t *buf);
void tsf_buf_reader_reset(tsf_buf_rdr_t *buf);
* if keep_fd is tsf_true, the file descriptor will be closed if: an error
* occurs while trying to create the buffer, and when the buffer is destroyed. */
tsf_buf_wtr_t* tsf_buf_writer_create(int fd,
uint32_t buf_size,
tsf_bool_t keep_fd);
* is closed. note that this operation does not result in the
* buffer being flushed, so calling this without calling the
* flush function (see below) first may result in data loss. */
void tsf_buf_writer_destroy(tsf_buf_wtr_t *buf);
* if you actually want to put this writer to good use. */
tsf_bool_t tsf_buf_writer_write(void *buf,
const void *data,
uint32_t len);
tsf_bool_t tsf_buf_writer_flush(tsf_buf_wtr_t *buf);
* result in illegal argument errors in tsf_zip_reader_create() and
* tsf_zip_writer_create(). however, tsf_stream_file_input and
* tsf_stream_file_output will gracefully accept it and take it
* to mean that normal buffered IO should be performed. */
void tsf_zip_wtr_attr_get_default(tsf_zip_wtr_attr_t *attr);
* default settings (a compression level of Z_DEFAULT_COMPRESSION and
* advanced_init set to false). this function will return tsf_true
* if ZLib is supported, and tsf_false otherwise. if tsf_false is
* returned, the error will be set to TSF_E_NOT_SUPPORTED. to make
* life easier in some cases, you can pass NULL to this function and
* the function will still perform the check if Zlib is supported. */
tsf_bool_t tsf_zip_wtr_attr_get_zlib_default(tsf_zip_wtr_attr_t *attr);
* used with default settings (blockSize100k = 9, verbosity = 0,
* workFactor = 0, small = 0). this function will return tsf_true
* if libbzip2 is supported, and tsf_false otherwise. if tsf_false
* is returned, the error will be set to TSF_E_NOT_SUPPORTED. to
* make life easier in some cases, you can pass NULL to this function
* and the function will still perform the check if libbzip2 is
* supported. */
tsf_bool_t tsf_zip_wtr_attr_get_bzip2_default(tsf_zip_wtr_attr_t *attr);
tsf_bool_t tsf_zip_wtr_attr_get_for_mode(tsf_zip_wtr_attr_t *attr,
tsf_zip_mode_t mode);
* complression schemes that are actually supported. */
void tsf_zip_rdr_attr_get_default(tsf_zip_rdr_attr_t *attr);
* allow bits to false, but all of the other fields are set to the
* default settings - so this is the perfect starting place if you want
* to enable only your approved compression schemes (just call this
* and then set the bits of the schemes that make you happy). */
void tsf_zip_rdr_attr_get_nozip(tsf_zip_rdr_attr_t *attr);
tsf_bool_t tsf_zip_rdr_attr_is_nozip(tsf_zip_rdr_attr_t *attr);
#define tsf_zlib_supported() \
(tsf_zip_wtr_attr_get_zlib_default(NULL))
#define tsf_libbzip2_supported() \
(tsf_zip_wtr_attr_get_bzip2_default(NULL))
* reader as a delegate to actually read the data. as such, this thing
* can adapt to many different underlying devices. returns an error
* if you try to use a mode or attribute set that is not supported.
* In particular, using TSF_ZIP_NONE is not supported!
*
* note that this function does not check if the selected mode is allowed
* according to the attributes. it is the caller's responsibility to
* ensure that the mode is allowed. */
tsf_zip_rdr_t* tsf_zip_reader_create(tsf_partial_reader_t reader,
void *reader_arg,
tsf_zip_mode_t mode,
const tsf_zip_rdr_attr_t *attr);
void tsf_zip_reader_destroy(tsf_zip_rdr_t *reader);
tsf_bool_t tsf_zip_reader_read(void *reader,
void *data,
uint32_t len);
* as a delegate to actually write the data. as such, this thing can
* adapt to many different underlying devices. note that it makes little
* or no sense to pass in a buffering writer, since this writer already
* does buffering (in fact, it has to do buffering to interact with the
* underlying compression engine). returns an error if you try to use
* a mode or attribute set that is not supported. in particular,
* TSF_ZIP_NONE is not supported! */
tsf_zip_wtr_t* tsf_zip_writer_create(tsf_writer_t writer,
void *writer_arg,
const tsf_zip_wtr_attr_t *attr);
void tsf_zip_writer_destroy(tsf_zip_wtr_t *writer);
tsf_bool_t tsf_zip_writer_write(void *writer,
const void *data,
uint32_t len);
* call it only if you really have to. if the full_flush parameter is
* true, the flush will not only be complete enough to allow the reading
* end to get all of the data, but will also result in the compressor
* resetting its state (so to speak) in order to make all future data
* be independant of the already written data. passing tsf_true for
* full_flush will help error recovery but will hurt your compression
* ratios even more.
*
* note that when using libbzip2, full_flush is ignored. in general,
* any flushing done with libbzip2 will hurt a lot more than any flushing
* done with zlib, regardless of the value of full_flush. so keep that
* in mind. in many cases, the extremely bad performance that results
* from flushing in libbzip2 will be sufficient reason to use zlib
* instead. */
tsf_bool_t tsf_zip_writer_flush(tsf_zip_wtr_t *writer,
tsf_bool_t full_flush);
* stream marker. this also does an implicit flush, so calling flush
* just before calling finish will not help (it shouldn't hurt, either).
* not that if you do a flush but do not do a finish, the receiver
* should be able to get all of the data but will probably report an
* error at the end of the file, complaining that the end of stream was
* never really hit.
*
* after finish returns, you may not use this writer anymore.
* attempting to call writer, flush, or finish on a writer that has
* already had finish called on it will lead to unpredictable behavior.
* after calling finish, you should just call destroy. */
tsf_bool_t tsf_zip_writer_finish(tsf_zip_wtr_t *writer);
* between different zipping strategies (including no zipping) as the input
* data indicates. however, it only works under two non-trivial
* conditions:
* 1) the input is formatted according to the serial protocol with
* stream file headers indicating compression settings, and
* 2) you call tsf_adaptive_reader_hint_switch() at the right times. */
tsf_adpt_rdr_t* tsf_adaptive_reader_create(tsf_partial_reader_t reader,
void *reader_arg,
uint32_t nozip_buf_size,
const tsf_zip_rdr_attr_t *attr);
void tsf_adaptive_reader_destroy(tsf_adpt_rdr_t *reader);
* if we are currently reading with compression turned off, this hint tells
* the reader to inspect the next four bytes to see if it contains a code
* corresponding to the start of a ZLIB or BZIP2 sequence. if we are using
* a ZLIB or BZIP2 reader, this specifies that an end-of-stream from the
* underlying reader is correct (otherwise it is flagged as erroneous). */
void tsf_adaptive_reader_hint_switch(tsf_adpt_rdr_t *reader);
uint32_t tsf_adaptive_reader_get_remaining(tsf_adpt_rdr_t *reader);
tsf_bool_t tsf_adaptive_reader_read(void *reader,
void *data,
uint32_t len);
* first four bytes. if the mode returned is TSF_ZIP_UNKNOWN then there
* was an error. if the error was TSF_E_NOT_SUPPORTED then the file is
* not in a valid TSF stream file format. */
tsf_zip_mode_t tsf_stream_file_get_mode(const char *filename);
* file descriptor. */
tsf_zip_mode_t tsf_stream_file_get_mode_from_fd(int fd);
* are set to the defaults. if the limits are NULL then no limits are used.
* instances of this type are not thread-safe; use locking around calls into
* the object. */
tsf_stream_file_input_t*
tsf_stream_file_input_open(const char *filename,
tsf_limits_t *limits,
tsf_zip_rdr_attr_t *attr);
* attributes are NULL then they are set to the defaults.
*
* if keep is true, the file descriptor will be closed when
* tsf_stream_file_input_close() is called. otherwise, the file
* descriptor will remain open. */
tsf_stream_file_input_t*
tsf_stream_file_input_fd_open(int fd,
tsf_limits_t *limits,
tsf_zip_rdr_attr_t *attr,
tsf_bool_t keep,
uint32_t buf_size);
void tsf_stream_file_input_close(tsf_stream_file_input_t *file);
* limitations. for example, mark & seek is not supported for compressed
* files. */
tsf_bool_t tsf_stream_file_input_allows_compression(tsf_stream_file_input_t *file);
* encounters a new type. */
tsf_bool_t tsf_stream_file_input_register_type_cback(tsf_stream_file_input_t *file,
tsf_type_cback_t cback,
void *arg);
* and void* argument. */
tsf_bool_t tsf_stream_file_input_unregister_type_cback(tsf_stream_file_input_t *file,
tsf_type_cback_t cback,
void *arg);
tsf_buffer_t* tsf_stream_file_input_read(tsf_stream_file_input_t *file);
* that you get to allocate. but you must treat it as an opaque!
*
* note that mark & seek is not supported for files that are compressed.
* it is also not supported if the underlying file descriptor does not
* support lseek(). if the file is compressed, you will get a
* TSF_E_NOT_SUPPORTED error. it is perfectly safe (and fast) to determine
* if a file is compressed by calling this function. you can of course
* also use tsf_stream_file_input_is_compressed(). if the file does not
* support lseek(), you will get some sort of system error, which may
* differ depending on how well your system complies to POSIX. :-) */
tsf_bool_t tsf_stream_file_input_get_mark(tsf_stream_file_input_t *file,
tsf_stream_file_mark_t *mark);
tsf_bool_t tsf_stream_file_input_seek(tsf_stream_file_input_t *file,
const tsf_stream_file_mark_t *mark);
* ones will be used (which means no compression). instances of this type
* are not thread-safe; use locking when calling its methods. */
tsf_stream_file_output_t*
tsf_stream_file_output_open(const char *filename,
tsf_bool_t append,
tsf_zip_wtr_attr_t *attr);
* file descriptor will be closed when tsf_stream_file_output_close() is
* called. otherwise, it will remain open. */
tsf_stream_file_output_t*
tsf_stream_file_output_fd_open(int fd,
tsf_zip_wtr_attr_t *attr,
tsf_bool_t keep,
uint32_t buf_size);
* went OK and tsf_false if it didn't. the file gets closed either way,
* though. */
tsf_bool_t tsf_stream_file_output_close(tsf_stream_file_output_t *file);
* at the point of failure and should not be used. */
tsf_bool_t tsf_stream_file_output_flush(tsf_stream_file_output_t *file);
* at the point of failure and should not be used. */
tsf_bool_t tsf_stream_file_output_write(tsf_stream_file_output_t *file,
tsf_buffer_t *buffer);
* storage optimized for storing huge values. additionally, a filesystem
* database allows a value to consist of a sequence of buffers (i.e. a
* stream), and it has support for connecting to a remote database.
*
* one of the main features of FSDB is its excellent concurrency support.
* even if an FSDB is opened by multiple different processes, or multiple
* threads in a single process, or multiple threads share the same
* tsf_fsdb_t* handle, the following properties are guaranteed:
*
* - tsf_fsdb_put() is not visible unless there is a subsequent
* tsf_fsdb_out_commit().
*
* - if multiple tsf_fsdb_out_commit()'s are run using the same key,
* then any tsf_fsdb_get()'s behave as if the only tsf_fsdb_put()
* and tsf_fsdb_out_commit() that had ever been executed was the last
* one at the time of the tsf_fsdb_get().
*
* - tsf_fsdb_get() returns a stream that does not change even if
* new tsf_fsdb_put()/tsf_fsdb_out_write()/tsf_fsdb_out_commit() are
* executed on the same key.
*
* - tsf_fsdb_out_abort() makes it appear as if the tsf_fsdb_put() and
* any subsequent tsf_fsdb_out_write()'s never happened.
*
* - if tsf_fsdb_out_commit() fails it is no different than if you had
* called tsf_fsdb_out_abort().
*
* These properties are guaranteed even when accessing the database
* using different tsf_fsdb_t* handles (even from separate processes),
* so long as the underlying filesystem supports the atomicity
* guarantees of open(O_EXCL) and rename().
*
* The memory management is such that the FSDB API never claims
* ownership of any objects, but the tsf_fsdb_t* must be kept alive so
* long as there are tsf_fsdb_in_t* or tsf_fsdb_out_t* that have been
* created from it. */
tsf_fsdb_t* tsf_fsdb_open_local(const char *dirname,
tsf_limits_t *limits,
tsf_zip_rdr_attr_t *zip_rdr_attr,
tsf_zip_wtr_attr_t *zip_wtr_attr,
tsf_bool_t update,
tsf_bool_t truncate);
tsf_fsdb_t* tsf_fsdb_open_remote(const char *host,
int port,
tsf_limits_t *limits,
tsf_zip_rdr_attr_t *zip_rdr_attr,
tsf_zip_wtr_attr_t *zip_wtr_attr);
void tsf_fsdb_close(tsf_fsdb_t *fsdb);
tsf_fsdb_out_t* tsf_fsdb_put(tsf_fsdb_t *fsdb,
tsf_buffer_t *key);
tsf_fsdb_in_t* tsf_fsdb_get(tsf_fsdb_t *fsdb,
tsf_buffer_t *key);
tsf_bool_t tsf_fsdb_rm(tsf_fsdb_t *fsdb,
tsf_buffer_t *key);
void tsf_fsdb_in_close(tsf_fsdb_in_t *in);
tsf_buffer_t* tsf_fsdb_in_read(tsf_fsdb_in_t *in);
* if this experiences an error, then it means that the stream is
* automatically aborted. */
tsf_bool_t tsf_fsdb_out_commit(tsf_fsdb_out_t *out);
void tsf_fsdb_out_abort(tsf_fsdb_out_t *out);
tsf_bool_t tsf_fsdb_out_write(tsf_fsdb_out_t *out,
tsf_buffer_t *buf);
#ifdef __cplusplus
};
#endif
#endif