mirror of
https://github.com/vale981/libblobpack
synced 2025-03-04 09:21:42 -05:00
update json api and docs
This commit is contained in:
parent
e4828f4e3a
commit
6e7300536a
8 changed files with 170 additions and 34 deletions
140
README.md
140
README.md
|
@ -8,6 +8,12 @@ The blobs are packed in platform independent format so you can use blobpack to
|
|||
pack data on one platform and then unpack it on a different one regardless of
|
||||
it's endianness.
|
||||
|
||||
Blobpack shall be used strictly for serialization and deserialization of
|
||||
arbitrary structured data. Supporting runtime representation of data with
|
||||
support for modifying/inserting fields shall not be supported to keep library
|
||||
simple and fast. You may keep readonly represetation of data as blobs but you
|
||||
should not attempt to use blobs for storing values that change.
|
||||
|
||||
Data Types
|
||||
-------------
|
||||
|
||||
|
@ -15,18 +21,43 @@ Blobpack API shall be agnostic of actual packing implementation and shall
|
|||
present the user with ability to pack following types:
|
||||
|
||||
- int: [ −9223372036854775807, +9223372036854775807 ] range
|
||||
- float: double precision float
|
||||
- real: double precision float
|
||||
- string: an array of characters with 0 at the end
|
||||
- array: an aggregation of any number of fields of any type
|
||||
- table: an aggregation of any number of fields where each element is a pair of string and any other type
|
||||
- table: an aggregation of any number of fields where each element is a pair of
|
||||
string and any other type
|
||||
|
||||
Internally the types shall be packed to balance quick unpacking with space efficiency.
|
||||
Internally the types shall be packed to balance quick unpacking with space
|
||||
efficiency.
|
||||
|
||||
The format is intentionally made to include length even on fixed length types
|
||||
like integers to simplify and speed up packing and unpacking. Some
|
||||
optimizations can of course be done to the packing format, but at current time
|
||||
such optimizations are deemed to be unnecessary because the gains are marginal.
|
||||
|
||||
JSON Support
|
||||
------------
|
||||
|
||||
All blobs shall be exportable and importable to and from JSON. Binary data
|
||||
shall be encoded as base64 strings.
|
||||
|
||||
The mapping between blobpack types and json types is as follows:
|
||||
|
||||
+-----------------------------+
|
||||
| blobpack | JSON |
|
||||
+-----------------------------+
|
||||
| BLOB_FIELD_BINARY | base64 |
|
||||
| BLOB_FIELD_STRING | string |
|
||||
| BLOB_FIELD_INT8 | number |
|
||||
| BLOB_FIELD_INT16 | number |
|
||||
| BLOB_FIELD_INT32 | number |
|
||||
| BLOB_FIELD_INT64 | number |
|
||||
| BLOB_FIELD_FLOAT32 | number |
|
||||
| BLOB_FIELD_FLOAT64 | number |
|
||||
| BLOB_FIELD_ARRAY | array |
|
||||
| BLOB_FIELD_TABLE | object |
|
||||
+-----------------------------+
|
||||
|
||||
Validation
|
||||
----------
|
||||
|
||||
|
@ -58,6 +89,10 @@ point numbers for the sake of performance.
|
|||
Note: the performance hit of casting numbers to long long is marginal enough
|
||||
even on mips, to be ignored completely for the sake of a clean api.
|
||||
|
||||
Note nr2: even though currently smallest size of number in blobpack is 4 byte
|
||||
(32 bit), we still pack small integers as int8 inside a 4 byte memory area
|
||||
because the packing format may be altered in the future to be more efficient.
|
||||
|
||||
Blobpack packs fields into a blob buffer. Each field has a 4 byte
|
||||
header containing attribyte type and length of the whole field including
|
||||
both header and data. If NAME bit is set then the next two bytes are the length
|
||||
|
@ -79,11 +114,10 @@ The header consists of 4 bytes which have this layout:
|
|||
|
||||
- e: reserved
|
||||
- t: type of the field (see below)
|
||||
- s: size of whole field (header+name+data)
|
||||
- s: size of whole field (header+data)
|
||||
|
||||
Type can be one of the following:
|
||||
|
||||
BLOB_FIELD_ROOT: this is root element. For historical reasons it is has type of 0
|
||||
BLOB_FIELD_ARRAY: this element can only contain unnamed elements
|
||||
BLOB_FIELD_TABLE: this element can contain named elements
|
||||
BLOB_FIELD_BINARY: a binary blob. We don't care about content (never included in json!)
|
||||
|
@ -106,9 +140,99 @@ elements.
|
|||
API Reference
|
||||
-------------
|
||||
|
||||
//! Initializes a blob_buf structure. Optionally takes memory area to be copied into the buffer which must represent a valid blob buf.
|
||||
void blob_buf_init(struct blob_buf *buf, const char *data, size_t size);
|
||||
|
||||
//! Initializes a blob_buf structure. Optionally takes memory area to be
|
||||
//! copied into the buffer which must represent a valid blob buf.
|
||||
//! if data is NULL and size is > 0 then the library shall create an empty
|
||||
//! memory area of the size "size" to avoid allocating more memory until the
|
||||
//! contents of the blob no longer can fit inside this memory area.
|
||||
|
||||
void blob_init(struct blob_buf *buf, const char *data, size_t size);
|
||||
|
||||
//! deletes memroy associated with this buffer
|
||||
|
||||
void blob_free(struct blob *buf);
|
||||
|
||||
//! Resets header but does not deallocate any memory.
|
||||
|
||||
void blob_reset(struct blob *buf);
|
||||
|
||||
//! Resizes the buffer. Can only be used to increase size.
|
||||
|
||||
bool blob_resize(struct blob *buf, int newsize);
|
||||
|
||||
//! returns the full size of the buffer memory including padding
|
||||
|
||||
static inline size_t blob_size(struct blob *self){ return blob_field_raw_pad_len(blob_head(self)); }
|
||||
|
||||
//! puts a string into the blob buffer
|
||||
|
||||
struct blob_field *blob_put_string(struct blob *self, const char *str);
|
||||
|
||||
Array/Table functions
|
||||
---------------------
|
||||
|
||||
The following functions open a new nested element and return a "tag" to this element which can be used later to close the element.
|
||||
|
||||
//! opens an array element
|
||||
|
||||
blob_offset_t blob_open_array(struct blob *buf);
|
||||
|
||||
//! closes an array element
|
||||
|
||||
void blob_close_array(struct blob *buf, blob_offset_t);
|
||||
|
||||
//! opens an table element
|
||||
|
||||
blob_offset_t blob_open_table(struct blob *buf);
|
||||
|
||||
//! closes an table element
|
||||
|
||||
void blob_close_table(struct blob *buf, blob_offset_t);
|
||||
|
||||
Write Functions
|
||||
---------------
|
||||
|
||||
Writing to the buffer is always done at the end of the buffer. Functionality to
|
||||
insert elements has been intentionally left out. Reading is done by reading
|
||||
elements directly from a blob field to which they belong (all elements always
|
||||
belong to a field, top level elements belong to root field which can be
|
||||
retreived using blob\_head(buffer);
|
||||
|
||||
//! write a boolean into the buffer
|
||||
struct blob_field *blob_put_bool(struct blob *buf, bool val);
|
||||
|
||||
//! write a string into the buffer
|
||||
struct blob_field *blob_put_string(struct blob *buf, const char *str);
|
||||
|
||||
//! write binary data into the buffer
|
||||
struct blob_field *blob_put_binary(struct blob *buf, const char *data, size_t size);
|
||||
|
||||
//! write a number into the buffer
|
||||
struct blob_field *blob_put_int(struct blob *buf, long long val);
|
||||
|
||||
//! write a real into the buffer
|
||||
struct blob_field *blob_put_real(struct blob *buf, double value);
|
||||
|
||||
//! write a raw attribute into the buffer
|
||||
struct blob_field *blob_put_attr(struct blob *buf, struct blob_field *attr);
|
||||
|
||||
//! print out the whole buffer
|
||||
void blob_dump(struct blob *self);
|
||||
|
||||
Reading/Writing JSON
|
||||
--------------------
|
||||
|
||||
//! allocate a string and return it filled with json representation
|
||||
char *blob_to_json(struct blob *buf);
|
||||
|
||||
//! convert json element to blob_field and write it to the blob
|
||||
bool blob_put_json(struct blob *buf, const char *json);
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
//! dump blob buffer contents to console using detailed info.
|
||||
|
||||
Packing data
|
||||
------------
|
||||
|
||||
|
|
15
blob.h
15
blob.h
|
@ -106,11 +106,22 @@ struct blob_field *blob_put_u64(struct blob *buf, uint64_t val);
|
|||
#define blob_put_i64 blob_put_u64
|
||||
*/
|
||||
|
||||
//! write a boolean into the buffer
|
||||
struct blob_field *blob_put_bool(struct blob *buf, bool val);
|
||||
struct blob_field *blob_put_int(struct blob *buf, long long val);
|
||||
struct blob_field *blob_put_float(struct blob *buf, double value);
|
||||
|
||||
//! write a string into the buffer
|
||||
struct blob_field *blob_put_string(struct blob *buf, const char *str);
|
||||
|
||||
//! write binary data into the buffer
|
||||
struct blob_field *blob_put_binary(struct blob *buf, const void *data, unsigned int size);
|
||||
|
||||
//! write a number into the buffer
|
||||
struct blob_field *blob_put_int(struct blob *buf, long long val);
|
||||
|
||||
//! write a real into the buffer
|
||||
struct blob_field *blob_put_real(struct blob *buf, double value);
|
||||
|
||||
//! write a raw attribute into the buffer
|
||||
struct blob_field *blob_put_attr(struct blob *buf, struct blob_field *attr);
|
||||
|
||||
//! print out the whole buffer
|
||||
|
|
|
@ -205,7 +205,7 @@ long long blob_field_get_int(const struct blob_field *self){
|
|||
return 0;
|
||||
}
|
||||
|
||||
double blob_field_get_float(const struct blob_field *self){
|
||||
double blob_field_get_real(const struct blob_field *self){
|
||||
int type = blob_field_type(self);
|
||||
switch(type){
|
||||
case BLOB_FIELD_INT8: return blob_field_get_i8(self);
|
||||
|
|
|
@ -40,7 +40,7 @@ uint32_t blob_field_raw_pad_len(const struct blob_field *attr);
|
|||
|
||||
bool blob_field_get_bool(const struct blob_field *self);
|
||||
long long int blob_field_get_int(const struct blob_field *self);
|
||||
double blob_field_get_float(const struct blob_field *self);
|
||||
double blob_field_get_real(const struct blob_field *self);
|
||||
const char *blob_field_get_string(const struct blob_field *self);
|
||||
|
||||
/*
|
||||
|
|
27
blob_json.c
27
blob_json.c
|
@ -20,7 +20,7 @@
|
|||
#include <json-c/json.h>
|
||||
|
||||
typedef const char *(*blob_json_format_t)(void *priv, struct blob_field *attr);
|
||||
|
||||
/*
|
||||
bool blob_put_json_object(struct blob *b, json_object *obj)
|
||||
{
|
||||
json_object_object_foreach(obj, key, val) {
|
||||
|
@ -88,13 +88,6 @@ static bool __blob_add_json(struct blob *b, json_object *obj)
|
|||
return false;
|
||||
|
||||
ret = blob_put_json_element(b, obj);
|
||||
/*
|
||||
if (json_object_get_type(obj) == json_type_object){
|
||||
ret = blob_put_json_object(b, obj);
|
||||
} else {
|
||||
ret = blob_put_json_array(b, json_object_get_array(obj));
|
||||
}
|
||||
*/
|
||||
json_object_put(obj);
|
||||
return ret;
|
||||
}
|
||||
|
@ -106,7 +99,7 @@ bool blob_put_json_from_file(struct blob *b, const char *file){
|
|||
bool blob_put_json_from_string(struct blob *b, const char *str){
|
||||
return __blob_add_json(b, json_tokener_parse(str));
|
||||
}
|
||||
|
||||
*/
|
||||
struct strbuf {
|
||||
int len;
|
||||
int pos;
|
||||
|
@ -335,24 +328,28 @@ char *blob_format_json_with_cb(struct blob_field *attr, bool list, blob_json_for
|
|||
return s.buf;
|
||||
}
|
||||
|
||||
char *blob_format_json(struct blob_field *attr, bool list){
|
||||
return blob_format_json_with_cb(attr, list, NULL, NULL, -1);
|
||||
char *blob_field_to_json(struct blob_field *attr){
|
||||
return blob_format_json_with_cb(attr, false, NULL, NULL, -1);
|
||||
}
|
||||
|
||||
char *blob_format_json_indent(struct blob_field *attr, bool list, int indent){
|
||||
return blob_format_json_with_cb(attr, list, NULL, NULL, indent);
|
||||
char *blob_field_to_json_pretty(struct blob_field *attr){
|
||||
return blob_format_json_with_cb(attr, false, NULL, NULL, 1);
|
||||
}
|
||||
|
||||
static void _blob_field_dump_json(struct blob_field *self, int indent){
|
||||
assert(self);
|
||||
char *json = blob_format_json_indent(self, true, indent);
|
||||
char *json = NULL;
|
||||
if(indent == 1)
|
||||
json = blob_field_to_json(self);
|
||||
else
|
||||
json = blob_field_to_json_pretty(self);
|
||||
printf("%s\n", json);
|
||||
free(json);
|
||||
}
|
||||
|
||||
void blob_field_dump_json(struct blob_field *self){
|
||||
assert(self);
|
||||
_blob_field_dump_json(self, -1);
|
||||
_blob_field_dump_json(self, 0);
|
||||
}
|
||||
|
||||
void blob_field_dump_json_pretty(struct blob_field *self){
|
||||
|
|
|
@ -20,18 +20,23 @@ struct json_object;
|
|||
|
||||
#include <stdbool.h>
|
||||
#include "blob.h"
|
||||
|
||||
/*
|
||||
bool blob_put_json_object(struct blob *b, struct json_object *obj);
|
||||
bool blob_put_json_element(struct blob *b, struct json_object *obj);
|
||||
bool blob_put_json_from_string(struct blob *b, const char *str);
|
||||
bool blob_put_json_from_file(struct blob *b, const char *file);
|
||||
|
||||
char *blob_format_json(struct blob_field *attr, bool list);
|
||||
char *blob_format_json_indent(struct blob_field *attr, bool list, int indent);
|
||||
*/
|
||||
|
||||
void blob_field_dump_json(struct blob_field *self);
|
||||
void blob_field_dump_json_pretty(struct blob_field *self);
|
||||
|
||||
static inline void blob_dump_json(struct blob *self){ blob_field_dump_json(blob_head(self)); }
|
||||
|
||||
char *blob_field_to_json(struct blob_field *self);
|
||||
static inline char *blob_to_json(struct blob *self){ return blob_field_to_json(blob_head(self)); }
|
||||
|
||||
bool blob_put_json(struct blob *self, const char *json);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ static void dump_attr_data(struct blob_field *data, int indent, int next_indent)
|
|||
break;
|
||||
case BLOB_FIELD_FLOAT32:
|
||||
case BLOB_FIELD_FLOAT64:
|
||||
indent_printf(indent, "%Le\n", (long double) blob_field_get_float(data));
|
||||
indent_printf(indent, "%Le\n", (long double) blob_field_get_real(data));
|
||||
break;
|
||||
case BLOB_FIELD_TABLE:
|
||||
case BLOB_FIELD_ARRAY:
|
||||
|
@ -157,7 +157,7 @@ int main(int argc, char **argv)
|
|||
|
||||
blob_dump(&buf);
|
||||
dump_message(&buf);
|
||||
char *json = blob_format_json(blob_head(&buf), false);
|
||||
char *json = blob_to_json(&buf);
|
||||
printf("json: %s\n", json);
|
||||
free(json);
|
||||
const char *sig = "{sv}s[{si}]";
|
||||
|
@ -183,7 +183,7 @@ int main(int argc, char **argv)
|
|||
// test the normal encoder/decoder
|
||||
blob_reset(&buf);
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
blob_put_json_from_string(&buf, json);
|
||||
blob_put_json(&buf, json);
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
printf("encode jsconc: %s\n", json);
|
||||
printf("time taken %lums\n", (end.tv_nsec - start.tv_nsec) / 1000);
|
||||
|
|
|
@ -490,8 +490,7 @@ int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, const char
|
|||
#define Buffer_AppendCharUnchecked(__enc, __chr) \
|
||||
*((__enc)->offset++) = __chr; \
|
||||
|
||||
FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC strreverse(char* begin, char* end)
|
||||
{
|
||||
static void strreverse(char* begin, char* end){
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
|
|
Loading…
Add table
Reference in a new issue