From b3f9b25d53b1bd1fc83e8a291ae40b84d02a4478 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Tue, 13 Nov 2018 15:33:56 +0100 Subject: prototest: add ubjson --- include/lib/ubjson/ubj.h | 231 ++++++++++++++++++++++++++++++++++++++ include/lib/ubjson/ubj_internal.h | 163 +++++++++++++++++++++++++++ 2 files changed, 394 insertions(+) create mode 100644 include/lib/ubjson/ubj.h create mode 100644 include/lib/ubjson/ubj_internal.h (limited to 'include') diff --git a/include/lib/ubjson/ubj.h b/include/lib/ubjson/ubj.h new file mode 100644 index 0000000..f3d5ac8 --- /dev/null +++ b/include/lib/ubjson/ubj.h @@ -0,0 +1,231 @@ +#ifndef UBJ_H +#define UBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef enum +{ + UBJ_MIXED=0, //NOT a type...or the type is mixed + + UBJ_NULLTYPE, + UBJ_NOOP, + UBJ_BOOL_TRUE, + UBJ_BOOL_FALSE, + + UBJ_CHAR, + UBJ_STRING, + UBJ_HIGH_PRECISION, + + UBJ_INT8, + UBJ_UINT8 , + UBJ_INT16, + UBJ_INT32, + UBJ_INT64, + UBJ_FLOAT32 , + UBJ_FLOAT64, + + UBJ_ARRAY, + UBJ_OBJECT, + + UBJ_NUM_TYPES //this is the size of how many types there are (chris' trick) +} UBJ_TYPE; + + + +//////////here is the declarations for the writer API//////////////////////////////////// + + + +///////////////////////////////////////////////////////////////////////////////////////// + +struct ubjw_context_t_s; +typedef struct ubjw_context_t_s ubjw_context_t; + +ubjw_context_t* ubjw_open_callback(void* userdata, + size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata), + int(*close_cb)(void* userdata), + void(*error_cb)(const char* error_msg) + ); +ubjw_context_t* ubjw_open_file(FILE*); +ubjw_context_t* ubjw_open_memory(uint8_t* dst_b, uint8_t* dst_e); + +size_t ubjw_close_context(ubjw_context_t* ctx); + +void ubjw_write_string(ubjw_context_t* dst, const char* out); +void ubjw_write_char(ubjw_context_t* dst, char out); + +void ubjw_write_uint8(ubjw_context_t* dst, uint8_t out); +void ubjw_write_int8(ubjw_context_t* dst, int8_t out); +void ubjw_write_int16(ubjw_context_t* dst, int16_t out); +void ubjw_write_int32(ubjw_context_t* dst, int32_t out); +void ubjw_write_int64(ubjw_context_t* dst, int64_t out); +void ubjw_write_high_precision(ubjw_context_t* dst, const char* hp); + +void ubjw_write_integer(ubjw_context_t* dst, int64_t out); +UBJ_TYPE ubjw_min_integer_type(int64_t in); + +void ubjw_write_float32(ubjw_context_t* dst, float out); +void ubjw_write_float64(ubjw_context_t* dst, double out); + +void ubjw_write_floating_point(ubjw_context_t* dst, double out); + +void ubjw_write_noop(ubjw_context_t* dst); +void ubjw_write_null(ubjw_context_t* dst); +void ubjw_write_bool(ubjw_context_t* dst, uint8_t out); + +void ubjw_begin_array(ubjw_context_t* dst, UBJ_TYPE type, size_t count); + +void ubjw_begin_object(ubjw_context_t* dst, UBJ_TYPE type, size_t count); +void ubjw_write_key(ubjw_context_t* dst, const char* key); +void ubjw_end(ubjw_context_t* dst); + +//output an efficient buffer of types +void ubjw_write_buffer(ubjw_context_t* dst, const uint8_t* data, UBJ_TYPE type, size_t count); + +//Proposal for N-D arrays +void ubjw_begin_ndarray(ubjw_context_t* dst, UBJ_TYPE type, const size_t* dims, uint8_t ndims); +void ubjw_write_ndbuffer(ubjw_context_t* dst,const uint8_t* data, UBJ_TYPE type, const size_t* dims, uint8_t ndims); + + +//////////here is the declarations for the reader API//////////////////////////////////// + + + +///////////////////////////////////////////////////////////////////////////////////////// + +struct ubjr_context_t_s; +typedef struct ubjr_context_t_s ubjr_context_t; + +//Open up a reader context for reading using a custom calllback +ubjr_context_t* ubjr_open_callback(void* userdata, + size_t(*read_cb)(void* data, size_t size, size_t count, void* userdata), + int(*peek_cb)(void* userdata), + int(*close_cb)(void* userdata), + void(*error_cb)(const char* error_msg) + ); + +//Open a context initialized to a UBJ file +ubjr_context_t* ubjr_open_file(FILE*); + +//Open up a context initialized to a memory dump of a UBJ file (or a segment of a UBJ file) +ubjr_context_t* ubjr_open_memory(const uint8_t* dst_b, const uint8_t* dst_e); + +//Close a reader context +size_t ubjr_close_context(ubjr_context_t* ctx); + +typedef char* ubjr_string_t; + +//An array that you read from the stream +typedef struct ubjr_array_t_s +{ + uint8_t originally_sized; + UBJ_TYPE type; + size_t size; //total number of elements + void* values; + uint8_t num_dims; + size_t* dims; //this could be faster if it was constant size, but would also make the size of the dynamic object a LOT bigger + +} ubjr_array_t; + +//a map that you read from the stream +typedef struct ubjr_object_t_s +{ + uint8_t originally_sized; + UBJ_TYPE type; + size_t size; + void* values; + ubjr_string_t* keys; + void* metatable; //don't use this..only useful for computing object_lookup +} ubjr_object_t; + +//a dynamic type that you parsed. +typedef struct ubjr_dynamic_t_s +{ + UBJ_TYPE type; + union + { + uint8_t boolean; + double real; + int64_t integer; + ubjr_string_t string; + ubjr_array_t container_array; + ubjr_object_t container_object; + }; +} ubjr_dynamic_t; + +//Parse a dynamic object from the stream +ubjr_dynamic_t ubjr_read_dynamic(ubjr_context_t* ctx); +void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn); + +ubjr_dynamic_t ubjr_object_lookup(ubjr_object_t* obj, const char* key); +size_t ubjr_local_type_size(UBJ_TYPE typ);//should be equivalent to sizeof() +size_t ubjr_ndarray_index(const ubjr_array_t* arr, const size_t* indices); + + +//output an efficient buffer of types +///void ubjr_read_buffer(struct ubjr_context_t* dst, const uint8_t* data, UBJ_TYPE type, size_t count); + +void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn); +void ubjr_cleanup_array(ubjr_array_t* arr); +void ubjr_cleanup_object(ubjr_object_t* obj); + + + +///////UBJ_RW api + +void ubjrw_write_dynamic(ubjw_context_t* ctx, ubjr_dynamic_t dobj,uint8_t optimize); +//ubjrw_append_object(ubjw_context_t* ctx, ubjr_dynamic_t dobj); +//ubjrw_append_array(ubjw_context_t* ctx, ubjr_dynamic_t dobj); + +#ifdef __cplusplus +} + +/* +#include + +static size_t write_os(const void* data, size_t size, size_t count, void* userdata) +{ + size_t n = size*count; + reinterpret_cast(userdata)->write(data, n); + return n; +} +static void close_os(void* userdata) +{ + reinterpret_cast(userdata)->close(); +} + +static size_t read_is(void* data, size_t size, size_t count, void* userdata) +{ + size_t n = size*count; + reinterpret_cast(userdata)->read(data, n); + return n; +} +static int peek_is(void* userdata) +{ + return reinterpret_cast(userdata)->peek(); +} +static void close_is(void* userdata) +{ + reinterpret_cast(userdata)->close(); +} + +static ubjw_context_t* ubjw_open_stream(std::ostream& outstream) +{ + return ubjw_open_callback((void*)&outstream, write_os, close_os, NULL); +} + +static ubjr_context_t* ubjr_open_stream(std::istream& instream) +{ + return ubjr_open_callback((void*)&instream, read_is, peek_is, close_is, NULL); +} +*/ + + +#endif + +#endif diff --git a/include/lib/ubjson/ubj_internal.h b/include/lib/ubjson/ubj_internal.h new file mode 100644 index 0000000..fc61697 --- /dev/null +++ b/include/lib/ubjson/ubj_internal.h @@ -0,0 +1,163 @@ +#ifndef UBJ_INTERNAL_H +#define UBJ_INTERNAL_H + +#include "ubj.h" +#include +#include + +#if _MSC_VER +#define inline __inline +#endif + + +static const uint8_t UBJI_TYPEC_convert[UBJ_NUM_TYPES] = "\x00ZNTFCSHiUIlLdD[{"; + +static const int UBJI_TYPE_size[UBJ_NUM_TYPES] = + { -1, //MIXED + 0, //NULLTYPE + 0, //NOOP + 0, //BOOL_TRUE + 0, //BOOL_FALSE + 1, //CHAR + sizeof(const char*), //STRING + sizeof(const char*), //high-precision + 1, //INT8 + 1, //UINT8 + 2, //int16 + 4, //int32 + 8, //int64 + 4, //float32 + 8, //float64 + -1, //array + -1 //object + }; + +static const size_t UBJR_TYPE_localsize[UBJ_NUM_TYPES] = +{ + sizeof(ubjr_dynamic_t), //MIXED + 0, //NULLTYPE + 0, //NOOP + 0, //BOOL_TRUE + 0, //BOOL_FALSE + sizeof(ubjr_string_t), //CHAR + sizeof(ubjr_string_t), //STRING + sizeof(ubjr_string_t), //high-precision + sizeof(int8_t), //INT8 + sizeof(uint8_t), //UINT8 + sizeof(int16_t), //int16 + sizeof(int32_t), //int32 + sizeof(int64_t), //int64 + sizeof(float), //float32 + sizeof(double), //float64 + sizeof(ubjr_array_t), //array + sizeof(ubjr_object_t) //object +}; + +static inline void _to_bigendian16(uint8_t* outbuffer, uint16_t input) +{ + *outbuffer++ = (input >> 8); // Get top order byte (guaranteed endian-independent since machine registers) + *outbuffer++ = input & 0xFF; // Get bottom order byte +} +static inline void _to_bigendian32(uint8_t* outbuffer, uint32_t input) +{ + _to_bigendian16(outbuffer, (uint16_t)(input >> 16)); // Get top order 2 bytes + _to_bigendian16(outbuffer + 2, (uint16_t)(input & 0xFFFF)); // Get bottom order 2 bytes +} +static inline void _to_bigendian64(uint8_t* outbuffer, uint64_t input) +{ + _to_bigendian32(outbuffer, (uint32_t)(input >> 32)); + _to_bigendian32(outbuffer + 4, (uint32_t)(input & 0xFFFFFFFF)); +} + +static inline uint8_t _is_bigendian() +{ + int i = 1; + char *low = (char*)&i; + return *low ? 0 : 1; +} + +#define BUF_BIG_ENDIAN_SWAP(type,func,ptr,num) \ + { \ + size_t i;type* d = (type*)ptr; \ + for (i = 0; i < num; i++) \ + { \ + func((uint8_t*)&d[i], d[i]); \ + } \ + } \ + +static inline void buf_endian_swap(uint8_t* buf, size_t sz, size_t n) +{ + if (!_is_bigendian()) + { + switch (sz) + { + case 1: + case 0: + break; + case 2: + BUF_BIG_ENDIAN_SWAP(uint16_t, _to_bigendian16,buf,n); + break; + case 4: + BUF_BIG_ENDIAN_SWAP(uint32_t, _to_bigendian32,buf,n); + break; + case 8: + BUF_BIG_ENDIAN_SWAP(uint64_t, _to_bigendian64,buf,n); + break; + }; + } +} + +//warning...null-terminated strings are assumed...when this is not necessarily valid. FIXED: we don't use null-terminated strings in the reader (NOT FIXED...string type is awkward) +static inline ubjr_dynamic_t priv_ubjr_pointer_to_dynamic(UBJ_TYPE typ, const void* dat) +{ + ubjr_dynamic_t outdyn; + outdyn.type = typ; + size_t n = 1; + switch (typ) + { + case UBJ_NULLTYPE: + case UBJ_NOOP: + break; + case UBJ_BOOL_TRUE: + case UBJ_BOOL_FALSE: + outdyn.boolean = (typ == UBJ_BOOL_TRUE ? 1 : 0); + break; + case UBJ_HIGH_PRECISION: + case UBJ_STRING: + case UBJ_CHAR://possibly if char allocate, otherwise don't + outdyn.string = *(const ubjr_string_t*)dat; + break; + case UBJ_INT8: + outdyn.integer = *(const int8_t*)dat; + break; + case UBJ_UINT8: + outdyn.integer = *(const uint8_t*)dat; + break; + case UBJ_INT16: + outdyn.integer = *(const int16_t*)dat; + break; + case UBJ_INT32: + outdyn.integer = *(const int32_t*)dat; + break; + case UBJ_INT64: + outdyn.integer = *(const int64_t*)dat; + break; + case UBJ_FLOAT32: + outdyn.real = *(const float*)dat; + break; + case UBJ_FLOAT64: + outdyn.real = *(const double*)dat; + break; + case UBJ_ARRAY: + outdyn.container_array = *(const ubjr_array_t*)dat; + break; + case UBJ_OBJECT: + outdyn.container_object = *(const ubjr_object_t*)dat; + break; + case UBJ_MIXED: + outdyn = *(const ubjr_dynamic_t*)dat; + }; + return outdyn; +} + +#endif \ No newline at end of file -- cgit v1.2.3