summaryrefslogtreecommitdiff
path: root/include/lib/ubjson
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2018-11-13 15:33:56 +0100
committerDaniel Friesel <derf@finalrewind.org>2018-11-13 15:33:56 +0100
commitb3f9b25d53b1bd1fc83e8a291ae40b84d02a4478 (patch)
tree64a170a55f6f9b0c949339511db77b80abeb61f9 /include/lib/ubjson
parent36316c2e4a9dbeab28b97fa18fefc37eed4a6782 (diff)
prototest: add ubjson
Diffstat (limited to 'include/lib/ubjson')
-rw-r--r--include/lib/ubjson/ubj.h231
-rw-r--r--include/lib/ubjson/ubj_internal.h163
2 files changed, 394 insertions, 0 deletions
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<inttypes.h>
+#include<stdio.h>
+
+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<iostream>
+
+static size_t write_os(const void* data, size_t size, size_t count, void* userdata)
+{
+ size_t n = size*count;
+ reinterpret_cast<std::ostream*>(userdata)->write(data, n);
+ return n;
+}
+static void close_os(void* userdata)
+{
+ reinterpret_cast<std::ostream*>(userdata)->close();
+}
+
+static size_t read_is(void* data, size_t size, size_t count, void* userdata)
+{
+ size_t n = size*count;
+ reinterpret_cast<std::istream*>(userdata)->read(data, n);
+ return n;
+}
+static int peek_is(void* userdata)
+{
+ return reinterpret_cast<std::istream*>(userdata)->peek();
+}
+static void close_is(void* userdata)
+{
+ reinterpret_cast<std::istream*>(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 <stdlib.h>
+#include <string.h>
+
+#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