summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/prototest/Makefile.inc96
-rw-r--r--src/app/prototest/main.cc79
-rw-r--r--src/lib/binn.cc3372
-rw-r--r--src/lib/capnp-c/capn-malloc.cc424
-rw-r--r--src/lib/capnp-c/capn-stream.cc217
-rw-r--r--src/lib/capnp-c/capn.cc1117
-rw-r--r--src/lib/mpack/mpack.cc6440
-rw-r--r--src/lib/mpmalloc.cc42
-rw-r--r--src/lib/nanopb/pb_common.cc97
-rw-r--r--src/lib/nanopb/pb_decode.cc1528
-rw-r--r--src/lib/nanopb/pb_encode.cc893
-rw-r--r--src/lib/ubjson/ubjr.c525
-rw-r--r--src/lib/ubjson/ubjrw.c169
-rw-r--r--src/lib/ubjson/ubjw.c626
-rw-r--r--src/lib/xdr.cc188
-rw-r--r--src/lib/xdr16.cc216
16 files changed, 0 insertions, 16029 deletions
diff --git a/src/app/prototest/Makefile.inc b/src/app/prototest/Makefile.inc
deleted file mode 100644
index c088f6b..0000000
--- a/src/app/prototest/Makefile.inc
+++ /dev/null
@@ -1,96 +0,0 @@
-ifeq (${aspectc}, 1)
- CXX_FLAGS += --Xweaver -asrc/app/prototest/prototest.ah --Xcompiler
-endif
-
-ifeq (${prototest_bench_energy}, 1)
- loop ?= 1
- COMMON_FLAGS += -DPROTOTEST_BENCH_ENERGY
-endif
-
-ifeq (${prototest_bench_cycles}, 1)
- loop ?= 0
- arch_drivers += ,counter
- COMMON_FLAGS += -DPROTOTEST_BENCH_CYCLES
-endif
-
-ifneq (${prototest_include_global}, )
- COMMON_FLAGS += -DPROTOTEST_INCLUDE_GLOBAL=${prototest_include_global}
-endif
-
-ifneq (${prototest_include_local}, )
- COMMON_FLAGS += -DPROTOTEST_INCLUDE_LOCAL=${prototest_include_local}
-endif
-
-ifeq (${prototest_arduinojson}, 1)
- COMMON_FLAGS += -DPROTOTEST_ARDUINOJSON
-endif
-
-ifeq (${prototest_binn}, 1)
- COMMON_FLAGS += -DPROTOTEST_BINN
- CXX_TARGETS += src/lib/binn.cc
-endif
-
-ifeq (${prototest_capnproto_c}, 1)
- COMMON_FLAGS += -DPROTOTEST_CAPNPROTO_C
- CXX_TARGETS += src/app/prototest/capnp_c_bench.capnp.cc
- CXX_TARGETS += src/lib/capnp-c/capn.cc
- CXX_TARGETS += src/lib/capnp-c/capn-malloc.cc
- CXX_TARGETS += src/lib/capnp-c/capn-stream.cc
- INCLUDES += -Iinclude/lib/capnp-c
-endif
-
-ifeq (${prototest_manualjson}, 1)
- COMMON_FLAGS += -DPROTOTEST_MANUALJSON
-endif
-
-ifeq (${prototest_modernjson}, 1)
- COMMON_FLAGS += -DPROTOTEST_MODERNJSON
- ostream = 1
-endif
-
-ifeq (${prototest_mpack}, 1)
- COMMON_FLAGS += -DPROTOTEST_MPACK
- CXX_TARGETS += src/lib/mpack/mpack.cc
- INCLUDES += -Iinclude/lib/mpack
-endif
-
-ifeq (${prototest_nanopb}, 1)
- COMMON_FLAGS += -DPROTOTEST_NANOPB
- CXX_TARGETS += src/app/prototest/nanopbbench.pb.cc src/lib/nanopb/pb_common.cc
- CXX_TARGETS += src/lib/nanopb/pb_decode.cc src/lib/nanopb/pb_encode.cc
- INCLUDES += -Iinclude/lib/nanopb
-endif
-
-ifeq (${prototest_ubjson}, 1)
- COMMON_FLAGS += -DPROTOTEST_UBJSON
- C_TARGETS += src/lib/ubjson/ubjr.c src/lib/ubjson/ubjw.c
- INCLUDES += -Iinclude/lib/ubjson
-endif
-
-ifeq (${prototest_xdr}, 1)
- COMMON_FLAGS += -DPROTOTEST_XDR
- CXX_TARGETS += src/lib/xdr.cc
-endif
-
-ifeq (${prototest_xdr16}, 1)
- COMMON_FLAGS += -DPROTOTEST_XDR16
- CXX_TARGETS += src/lib/xdr16.cc
-endif
-
-# Don't try to make .capnp from .capnp.c
-%.capnp: ;
-
-# Don't try to make .proto from .proto.c
-%.proto: ;
-
-%.pb.cc: %.proto
- ${QUIET}protoc --plugin=protoc-gen-nanopb=${HOME}/var/ess/protocol-modeling/nanopb/generator/protoc-gen-nanopb --nanopb_out=. src/app/prototest/nanopbbench.proto
- ${QUIET}mv src/app/prototest/nanopbbench.pb.c src/app/prototest/nanopbbench.pb.cc
- ${QUIET}cp src/app/prototest/nanopbbench.pb.cc /tmp
- ${QUIET}sed -i 's!src/app/prototest/!!' src/app/prototest/nanopbbench.pb.cc
- ${QUIET}sed -i 's!\#include "src/app/prototest/nanopb.pb.h"!!' src/app/prototest/nanopbbench.pb.h
-
-%.capnp.cc: %.capnp
- ${QUIET}capnp compile -oc $<
- ${QUIET}mv $<.c $<.cc
- ${QUIET}cp $<.cc /tmp
diff --git a/src/app/prototest/main.cc b/src/app/prototest/main.cc
deleted file mode 100644
index 7fc897e..0000000
--- a/src/app/prototest/main.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "arch.h"
-#include "driver/gpio.h"
-#include "driver/stdout.h"
-
-#ifdef PROTOTEST_BENCH_CYCLES
-#include "driver/counter.h"
-#endif
-
-#ifdef PROTOTEST_ARDUINOJSON
-#include "lib/ArduinoJson.h"
-#endif
-#ifdef PROTOTEST_BINN
-#include "lib/binn.h"
-#endif
-#ifdef PROTOTEST_CAPNPROTO_C
-#include <capnp_c.h>
-#include "capnp_c_bench.capnp.h"
-#endif
-#ifdef PROTOTEST_MANUALJSON
-#include "object/stdbuf.h"
-#endif
-#ifdef PROTOTEST_MODERNJSON
-#include "lib/modernjson/json.h"
-#endif
-#ifdef PROTOTEST_MPACK
-#include "mpack.h"
-#endif
-#ifdef PROTOTEST_NANOPB
-#include <pb.h>
-#include "nanopbbench.pb.h"
-#include <pb_encode.h>
-#include <pb_decode.h>
-#endif
-#ifdef PROTOTEST_UBJSON
-#include "ubj.h"
-#endif
-#ifdef PROTOTEST_XDR
-#include "lib/xdr.h"
-#endif
-#ifdef PROTOTEST_XDR16
-#include "lib/xdr16.h"
-#endif
-
-#include <stdint.h>
-
-#ifdef PROTOTEST_INCLUDE_GLOBAL
-#include "prototest_global.cc.inc"
-#endif
-
-void loop(void)
-{
- //static uint16_t ts = 0;
- //ts++;
-
-#ifdef PROTOTEST_INCLUDE_LOCAL
-#include "prototest_local.cc.inc"
-#endif
-
-}
-
-int main(void)
-{
- arch.setup();
- gpio.setup();
- kout.setup();
-
- //gpio.led_on(0);
- kout << "Hello, World!" << endl;
-
-#if defined(PROTOTEST_BENCH_CYCLES) and !defined(PROTOTEST_ARCH_esp8266)
- while (1) {
- loop();
- }
-#else
- arch.idle_loop();
-#endif
-
- return 0;
-}
diff --git a/src/lib/binn.cc b/src/lib/binn.cc
deleted file mode 100644
index b7e4839..0000000
--- a/src/lib/binn.cc
+++ /dev/null
@@ -1,3372 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <memory.h>
-#include "lib/binn.h"
-
-#ifdef MULTIPASS_TRACE_MALLOC
-#include "lib/mpmalloc.h"
-#else
-#define mpmalloc malloc
-#define mprealloc realloc
-#define mpfree free
-#endif
-
-#define UNUSED(x) (void)(x)
-#define round(dbl) dbl >= 0.0 ? (int)(dbl + 0.5) : ((dbl - (double)(int)dbl) <= -0.5 ? (int)dbl : (int)(dbl - 0.5))
-
-// magic number: 0x1F 0xb1 0x22 0x1F => 0x1FB1221F or 0x1F22B11F
-// because the BINN_STORAGE_NOBYTES (binary 000) may not have so many sub-types (BINN_STORAGE_HAS_MORE = 0x10)
-#define BINN_MAGIC 0x1F22B11F
-
-#define MAX_BINN_HEADER 9 // [1:type][4:size][4:count]
-#define MIN_BINN_SIZE 3 // [1:type][1:size][1:count]
-#define CHUNK_SIZE 256 // 1024
-
-#define BINN_STRUCT 1
-#define BINN_BUFFER 2
-
-void* (*malloc_fn)(size_t len) = 0;
-void* (*realloc_fn)(void *ptr, size_t len) = 0;
-void (*free_fn)(void *ptr) = 0;
-
-/***************************************************************************/
-
-#if defined(__alpha__) || defined(__hppa__) || defined(__mips__) || defined(__powerpc__) || defined(__sparc__)
-#define BINN_ONLY_ALIGNED_ACCESS
-#elif ( defined(__arm__) || defined(__aarch64__) ) && !defined(__ARM_FEATURE_UNALIGNED)
-#define BINN_ONLY_ALIGNED_ACCESS
-#endif
-
-#if defined(_WIN32)
-#define BIG_ENDIAN 0x1000
-#define LITTLE_ENDIAN 0x0001
-#define BYTE_ORDER LITTLE_ENDIAN
-#elif defined(__APPLE__)
-/* macros already defined */
-#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
-#include <sys/endian.h>
-#elif defined(_AIX)
-#include <sys/machine.h>
-#else
-#include <endian.h>
-#endif
-
-#ifndef BYTE_ORDER
-#error "BYTE_ORDER not defined"
-#endif
-#ifndef BIG_ENDIAN
-#error "BIG_ENDIAN not defined"
-#endif
-#ifndef LITTLE_ENDIAN
-#error "LITTLE_ENDIAN not defined"
-#endif
-#if BIG_ENDIAN == LITTLE_ENDIAN
-#error "BIG_ENDIAN == LITTLE_ENDIAN"
-#endif
-#if BYTE_ORDER!=BIG_ENDIAN && BYTE_ORDER!=LITTLE_ENDIAN
-#error "BYTE_ORDER not supported"
-#endif
-
-typedef unsigned short int u16;
-typedef unsigned int u32;
-typedef unsigned long long int u64;
-
-BINN_PRIVATE void copy_be16(u16 *pdest, u16 *psource) {
-#if BYTE_ORDER == LITTLE_ENDIAN
- unsigned char *source = (unsigned char *) psource;
- unsigned char *dest = (unsigned char *) pdest;
- dest[0] = source[1];
- dest[1] = source[0];
-#else // if BYTE_ORDER == BIG_ENDIAN
-#ifdef BINN_ONLY_ALIGNED_ACCESS
- if (psource % 2 == 0){ // address aligned to 16 bit
- *pdest = *psource;
- } else {
- unsigned char *source = (unsigned char *) psource;
- unsigned char *dest = (unsigned char *) pdest;
- dest[0] = source[0]; // indexes are the same
- dest[1] = source[1];
- }
-#else
- *pdest = *psource;
-#endif
-#endif
-}
-
-BINN_PRIVATE void copy_be32(u32 *pdest, u32 *psource) {
-#if BYTE_ORDER == LITTLE_ENDIAN
- unsigned char *source = (unsigned char *) psource;
- unsigned char *dest = (unsigned char *) pdest;
- dest[0] = source[3];
- dest[1] = source[2];
- dest[2] = source[1];
- dest[3] = source[0];
-#else // if BYTE_ORDER == BIG_ENDIAN
-#ifdef BINN_ONLY_ALIGNED_ACCESS
- if (psource % 4 == 0){ // address aligned to 32 bit
- *pdest = *psource;
- } else {
- unsigned char *source = (unsigned char *) psource;
- unsigned char *dest = (unsigned char *) pdest;
- dest[0] = source[0]; // indexes are the same
- dest[1] = source[1];
- dest[2] = source[2];
- dest[3] = source[3];
- }
-#else
- *pdest = *psource;
-#endif
-#endif
-}
-
-BINN_PRIVATE void copy_be64(u64 *pdest, u64 *psource) {
-#if BYTE_ORDER == LITTLE_ENDIAN
- unsigned char *source = (unsigned char *) psource;
- unsigned char *dest = (unsigned char *) pdest;
- int i;
- for (i=0; i < 8; i++) {
- dest[i] = source[7-i];
- }
-#else // if BYTE_ORDER == BIG_ENDIAN
-#ifdef BINN_ONLY_ALIGNED_ACCESS
- if (psource % 8 == 0){ // address aligned to 64 bit
- *pdest = *psource;
- } else {
- unsigned char *source = (unsigned char *) psource;
- unsigned char *dest = (unsigned char *) pdest;
- int i;
- for (i=0; i < 8; i++) {
- dest[i] = source[i]; // indexes are the same
- }
- }
-#else
- *pdest = *psource;
-#endif
-#endif
-}
-
-/***************************************************************************/
-
-#ifndef WIN32
-#define stricmp strcasecmp
-#define strnicmp strncasecmp
-#endif
-
-/***************************************************************************/
-
-void APIENTRY binn_set_alloc_functions(void* (*new_malloc)(size_t), void* (*new_realloc)(void*,size_t), void (*new_free)(void*)) {
-
- malloc_fn = new_malloc;
- realloc_fn = new_realloc;
- free_fn = new_free;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE void check_alloc_functions() {
-
- if (malloc_fn == 0) malloc_fn = &mpmalloc;
- if (realloc_fn == 0) realloc_fn = &mprealloc;
- if (free_fn == 0) free_fn = &mpfree;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE void * binn_malloc(int size) {
- check_alloc_functions();
- return malloc_fn(size);
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE void * binn_memdup(void *src, int size) {
- void *dest;
-
- if (src == NULL || size <= 0) return NULL;
- dest = binn_malloc(size);
- if (dest == NULL) return NULL;
- memcpy(dest, src, size);
- return dest;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE size_t strlen2(char *str) {
-
- if (str == NULL) return 0;
- return strlen(str);
-
-}
-
-/***************************************************************************/
-
-int APIENTRY binn_create_type(int storage_type, int data_type_index) {
- if (data_type_index < 0) return -1;
- if ((storage_type < BINN_STORAGE_MIN) || (storage_type > BINN_STORAGE_MAX)) return -1;
- if (data_type_index < 16)
- return storage_type | data_type_index;
- else if (data_type_index < 4096) {
- storage_type |= BINN_STORAGE_HAS_MORE;
- storage_type <<= 8;
- data_type_index >>= 4;
- return storage_type | data_type_index;
- } else
- return -1;
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_get_type_info(int long_type, int *pstorage_type, int *pextra_type) {
- int storage_type, extra_type;
- BOOL retval=TRUE;
-
-again:
-
- if (long_type < 0) {
- goto loc_invalid;
- } else if (long_type <= 0xff) {
- storage_type = long_type & BINN_STORAGE_MASK;
- extra_type = long_type & BINN_TYPE_MASK;
- } else if (long_type <= 0xffff) {
- storage_type = long_type & BINN_STORAGE_MASK16;
- storage_type >>= 8;
- extra_type = long_type & BINN_TYPE_MASK16;
- extra_type >>= 4;
- } else if (long_type & BINN_STORAGE_VIRTUAL) {
- //storage_type = BINN_STORAGE_VIRTUAL;
- //extra_type = xxx;
- long_type &= 0xffff;
- goto again;
- } else {
-loc_invalid:
- storage_type = -1;
- extra_type = -1;
- retval = FALSE;
- }
-
- if (pstorage_type) *pstorage_type = storage_type;
- if (pextra_type) *pextra_type = extra_type;
-
- return retval;
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_create(binn *item, int type, int size, void *pointer) {
- BOOL retval=FALSE;
-
- switch (type) {
- case BINN_LIST:
- case BINN_MAP:
- case BINN_OBJECT:
- break;
- default:
- goto loc_exit;
- }
-
- if ((item == NULL) || (size < 0)) goto loc_exit;
- if (size < MIN_BINN_SIZE) {
- if (pointer) goto loc_exit;
- else size = 0;
- }
-
- memset(item, 0, sizeof(binn));
-
- if (pointer) {
- item->pre_allocated = TRUE;
- item->pbuf = pointer;
- item->alloc_size = size;
- } else {
- item->pre_allocated = FALSE;
- if (size == 0) size = CHUNK_SIZE;
- pointer = binn_malloc(size);
- if (pointer == 0) return INVALID_BINN;
- item->pbuf = pointer;
- item->alloc_size = size;
- }
-
- item->header = BINN_MAGIC;
- //item->allocated = FALSE; -- already zeroed
- item->writable = TRUE;
- item->used_size = MAX_BINN_HEADER; // save space for the header
- item->type = type;
- //item->count = 0; -- already zeroed
- item->dirty = TRUE; // the header is not written to the buffer
-
- retval = TRUE;
-
-loc_exit:
- return retval;
-
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_new(int type, int size, void *pointer) {
- binn *item;
-
- item = (binn*) binn_malloc(sizeof(binn));
-
- if (binn_create(item, type, size, pointer) == FALSE) {
- free_fn(item);
- return NULL;
- }
-
- item->allocated = TRUE;
- return item;
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_create_list(binn *list) {
-
- return binn_create(list, BINN_LIST, 0, NULL);
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_create_map(binn *map) {
-
- return binn_create(map, BINN_MAP, 0, NULL);
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_create_object(binn *object) {
-
- return binn_create(object, BINN_OBJECT, 0, NULL);
-
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_list() {
- return binn_new(BINN_LIST, 0, 0);
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_map() {
- return binn_new(BINN_MAP, 0, 0);
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_object() {
- return binn_new(BINN_OBJECT, 0, 0);
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_load(void *data, binn *value) {
-
- if ((data == NULL) || (value == NULL)) return FALSE;
- memset(value, 0, sizeof(binn));
- value->header = BINN_MAGIC;
- //value->allocated = FALSE; -- already zeroed
- //value->writable = FALSE;
-
- if (binn_is_valid(data, &value->type, &value->count, &value->size) == FALSE) return FALSE;
- value->ptr = data;
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-binn * APIENTRY binn_open(void *data) {
- binn *item;
-
- item = (binn*) binn_malloc(sizeof(binn));
-
- if (binn_load(data, item) == FALSE) {
- free_fn(item);
- return NULL;
- }
-
- item->allocated = TRUE;
- return item;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE int binn_get_ptr_type(void *ptr) {
-
- if (ptr == NULL) return 0;
-
- switch (*(unsigned int *)ptr) {
- case BINN_MAGIC:
- return BINN_STRUCT;
- default:
- return BINN_BUFFER;
- }
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_is_struct(void *ptr) {
-
- if (ptr == NULL) return FALSE;
-
- if ((*(unsigned int *)ptr) == BINN_MAGIC) {
- return TRUE;
- } else {
- return FALSE;
- }
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE int CalcAllocation(int needed_size, int alloc_size) {
- int calc_size;
-
- calc_size = alloc_size;
- while (calc_size < needed_size) {
- calc_size <<= 1; // same as *= 2
- //calc_size += CHUNK_SIZE; -- this is slower than the above line, because there are more reallocations
- }
- return calc_size;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL CheckAllocation(binn *item, int add_size) {
- int alloc_size;
- void *ptr;
-
- if (item->used_size + add_size > item->alloc_size) {
- if (item->pre_allocated) return FALSE;
- alloc_size = CalcAllocation(item->used_size + add_size, item->alloc_size);
- ptr = realloc_fn(item->pbuf, alloc_size);
- if (ptr == NULL) return FALSE;
- item->pbuf = ptr;
- item->alloc_size = alloc_size;
- }
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-#if BYTE_ORDER == BIG_ENDIAN
-
-BINN_PRIVATE int get_storage_size(int storage_type) {
-
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- return 0;
- case BINN_STORAGE_BYTE:
- return 1;
- case BINN_STORAGE_WORD:
- return 2;
- case BINN_STORAGE_DWORD:
- return 4;
- case BINN_STORAGE_QWORD:
- return 8;
- default:
- return 0;
- }
-
-}
-
-#endif
-
-/***************************************************************************/
-
-BINN_PRIVATE unsigned char * AdvanceDataPos(unsigned char *p, unsigned char *plimit) {
- unsigned char byte;
- int storage_type, DataSize;
-
- if (p > plimit) return 0;
-
- byte = *p; p++;
- storage_type = byte & BINN_STORAGE_MASK;
- if (byte & BINN_STORAGE_HAS_MORE) p++;
-
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- //p += 0;
- break;
- case BINN_STORAGE_BYTE:
- p ++;
- break;
- case BINN_STORAGE_WORD:
- p += 2;
- break;
- case BINN_STORAGE_DWORD:
- p += 4;
- break;
- case BINN_STORAGE_QWORD:
- p += 8;
- break;
- case BINN_STORAGE_BLOB:
- if (p + sizeof(int) - 1 > plimit) return 0;
- copy_be32((u32*)&DataSize, (u32*)p);
- p += 4 + DataSize;
- break;
- case BINN_STORAGE_CONTAINER:
- if (p > plimit) return 0;
- DataSize = *((unsigned char*)p);
- if (DataSize & 0x80) {
- if (p + sizeof(int) - 1 > plimit) return 0;
- copy_be32((u32*)&DataSize, (u32*)p);
- DataSize &= 0x7FFFFFFF;
- }
- DataSize--; // remove the type byte already added before
- p += DataSize;
- break;
- case BINN_STORAGE_STRING:
- if (p > plimit) return 0;
- DataSize = *((unsigned char*)p);
- if (DataSize & 0x80) {
- if (p + sizeof(int) - 1 > plimit) return 0;
- copy_be32((u32*)&DataSize, (u32*)p);
- DataSize &= 0x7FFFFFFF;
- p+=4;
- } else {
- p++;
- }
- p += DataSize;
- p++; // null terminator.
- break;
- default:
- return 0;
- }
-
- if (p > plimit) return 0;
-
- return p;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE unsigned char * SearchForID(unsigned char *p, int header_size, int size, int numitems, int id) {
- unsigned char *plimit, *base;
- int i, int32;
-
- base = p;
- plimit = p + size - 1;
- p += header_size;
-
- // search for the ID in all the arguments.
- for (i = 0; i < numitems; i++) {
- copy_be32((u32*)&int32, (u32*)p);
- p += 4;
- if (p > plimit) break;
- // Compare if the IDs are equal.
- if (int32 == id) return p;
- // xxx
- p = AdvanceDataPos(p, plimit);
- if ((p == 0) || (p < base)) break;
- }
-
- return NULL;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE unsigned char * SearchForKey(unsigned char *p, int header_size, int size, int numitems, char *key) {
- unsigned char len, *plimit, *base;
- int i, keylen;
-
- base = p;
- plimit = p + size - 1;
- p += header_size;
-
- keylen = strlen(key);
-
- // search for the key in all the arguments.
- for (i = 0; i < numitems; i++) {
- len = *((unsigned char *)p);
- p++;
- if (p > plimit) break;
- // Compare if the strings are equal.
- if (len > 0) {
- if (strnicmp((char*)p, key, len) == 0) { // note that there is no null terminator here
- if (keylen == len) {
- p += len;
- return p;
- }
- }
- p += len;
- if (p > plimit) break;
- } else if (len == keylen) { // in the case of empty string: ""
- return p;
- }
- // xxx
- p = AdvanceDataPos(p, plimit);
- if ((p == 0) || (p < base)) break;
- }
-
- return NULL;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL AddValue(binn *item, int type, void *pvalue, int size);
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL binn_list_add_raw(binn *item, int type, void *pvalue, int size) {
-
- if ((item == NULL) || (item->type != BINN_LIST) || (item->writable == FALSE)) return FALSE;
-
- //if (CheckAllocation(item, 4) == FALSE) return FALSE; // 4 bytes used for data_store and data_format.
-
- if (AddValue(item, type, pvalue, size) == FALSE) return FALSE;
-
- item->count++;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL binn_object_set_raw(binn *item, char *key, int type, void *pvalue, int size) {
- unsigned char *p, len;
- int int32;
-
- if ((item == NULL) || (item->type != BINN_OBJECT) || (item->writable == FALSE)) return FALSE;
-
- if (key == NULL) return FALSE;
- int32 = strlen(key);
- if (int32 > 255) return FALSE;
-
- // is the key already in it?
- p = SearchForKey((unsigned char*)item->pbuf, MAX_BINN_HEADER, item->used_size, item->count, key);
- if (p) return FALSE;
-
- // start adding it
-
- if (CheckAllocation(item, 1 + int32) == FALSE) return FALSE; // bytes used for the key size and the key itself.
-
- p = ((unsigned char *) item->pbuf) + item->used_size;
- len = int32;
- *p = len;
- p++;
- memcpy(p, key, int32);
- int32++; // now contains the strlen + 1 byte for the len
- item->used_size += int32;
-
- if (AddValue(item, type, pvalue, size) == FALSE) {
- item->used_size -= int32;
- return FALSE;
- }
-
- item->count++;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL binn_map_set_raw(binn *item, int id, int type, void *pvalue, int size) {
- unsigned char *p;
-
- if ((item == NULL) || (item->type != BINN_MAP) || (item->writable == FALSE)) return FALSE;
-
- // is the ID already in it?
- p = SearchForID((unsigned char*)item->pbuf, MAX_BINN_HEADER, item->used_size, item->count, id);
- if (p) return FALSE;
-
- // start adding it
-
- if (CheckAllocation(item, 4) == FALSE) return FALSE; // 4 bytes used for the id.
-
- p = ((unsigned char *) item->pbuf) + item->used_size;
- copy_be32((u32*)p, (u32*)&id);
- item->used_size += 4;
-
- if (AddValue(item, type, pvalue, size) == FALSE) {
- item->used_size -= 4;
- return FALSE;
- }
-
- item->count++;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE void * compress_int(int *pstorage_type, int *ptype, void *psource) {
- int storage_type, storage_type2, type, type2=0;
- int64 vint;
- uint64 vuint;
- char *pvalue;
-#if BYTE_ORDER == BIG_ENDIAN
- int size1, size2;
-#endif
-
- storage_type = *pstorage_type;
- if (storage_type == BINN_STORAGE_BYTE) return psource;
-
- type = *ptype;
-
- switch (type) {
- case BINN_INT64:
- vint = *(int64*)psource;
- goto loc_signed;
- case BINN_INT32:
- vint = *(int*)psource;
- goto loc_signed;
- case BINN_INT16:
- vint = *(short*)psource;
- goto loc_signed;
- case BINN_UINT64:
- vuint = *(uint64*)psource;
- goto loc_positive;
- case BINN_UINT32:
- vuint = *(unsigned int*)psource;
- goto loc_positive;
- case BINN_UINT16:
- vuint = *(unsigned short*)psource;
- goto loc_positive;
- }
-
-loc_signed:
-
- if (vint >= 0) {
- vuint = vint;
- goto loc_positive;
- }
-
-//loc_negative:
-
- if (vint >= INT8_MIN) {
- type2 = BINN_INT8;
- } else
- if (vint >= INT16_MIN) {
- type2 = BINN_INT16;
- } else
- if (vint >= INT32_MIN) {
- type2 = BINN_INT32;
- }
- goto loc_exit;
-
-loc_positive:
-
- if (vuint <= UINT8_MAX) {
- type2 = BINN_UINT8;
- } else
- if (vuint <= UINT16_MAX) {
- type2 = BINN_UINT16;
- } else
- if (vuint <= UINT32_MAX) {
- type2 = BINN_UINT32;
- }
-
-loc_exit:
-
- pvalue = (char *) psource;
-
- if ((type2) && (type2 != type)) {
- *ptype = type2;
- storage_type2 = binn_get_write_storage(type2);
- *pstorage_type = storage_type2;
-#if BYTE_ORDER == BIG_ENDIAN
- size1 = get_storage_size(storage_type);
- size2 = get_storage_size(storage_type2);
- pvalue += (size1 - size2);
-#endif
- }
-
- return pvalue;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE int type_family(int type);
-
-BINN_PRIVATE BOOL AddValue(binn *item, int type, void *pvalue, int size) {
- int int32, ArgSize, storage_type, extra_type;
- unsigned char *p;
-
- binn_get_type_info(type, &storage_type, &extra_type);
-
- if (pvalue == NULL) {
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- break;
- case BINN_STORAGE_BLOB:
- case BINN_STORAGE_STRING:
- if (size == 0) break; // the 2 above are allowed to have 0 length
- default:
- return FALSE;
- }
- }
-
- if ((type_family(type) == BINN_FAMILY_INT) && (item->disable_int_compression == FALSE))
- pvalue = compress_int(&storage_type, &type, pvalue);
-
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- size = 0;
- ArgSize = size;
- break;
- case BINN_STORAGE_BYTE:
- size = 1;
- ArgSize = size;
- break;
- case BINN_STORAGE_WORD:
- size = 2;
- ArgSize = size;
- break;
- case BINN_STORAGE_DWORD:
- size = 4;
- ArgSize = size;
- break;
- case BINN_STORAGE_QWORD:
- size = 8;
- ArgSize = size;
- break;
- case BINN_STORAGE_BLOB:
- if (size < 0) return FALSE;
- //if (size == 0) ...
- ArgSize = size + 4;
- break;
- case BINN_STORAGE_STRING:
- if (size < 0) return FALSE;
- if (size == 0) size = strlen2( (char *) pvalue);
- ArgSize = size + 5; // at least this size
- break;
- case BINN_STORAGE_CONTAINER:
- if (size <= 0) return FALSE;
- ArgSize = size;
- break;
- default:
- return FALSE;
- }
-
- ArgSize += 2; // at least 2 bytes used for data_type.
- if (CheckAllocation(item, ArgSize) == FALSE) return FALSE;
-
- // Gets the pointer to the next place in buffer
- p = ((unsigned char *) item->pbuf) + item->used_size;
-
- // If the data is not a container, store the data type
- if (storage_type != BINN_STORAGE_CONTAINER) {
- if (type > 255) {
- u16 type16 = type;
- copy_be16((u16*)p, (u16*)&type16);
- p += 2;
- item->used_size += 2;
- } else {
- *p = type;
- p++;
- item->used_size++;
- }
- }
-
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- // Nothing to do.
- break;
- case BINN_STORAGE_BYTE:
- *((char *) p) = *((char *) pvalue);
- item->used_size += 1;
- break;
- case BINN_STORAGE_WORD:
- copy_be16((u16*)p, (u16*)pvalue);
- item->used_size += 2;
- break;
- case BINN_STORAGE_DWORD:
- copy_be32((u32*)p, (u32*)pvalue);
- item->used_size += 4;
- break;
- case BINN_STORAGE_QWORD:
- copy_be64((u64*)p, (u64*)pvalue);
- item->used_size += 8;
- break;
- case BINN_STORAGE_BLOB:
- copy_be32((u32*)p, (u32*)&size);
- p += 4;
- memcpy(p, pvalue, size);
- item->used_size += 4 + size;
- break;
- case BINN_STORAGE_STRING:
- if (size > 127) {
- int32 = size | 0x80000000;
- copy_be32((u32*)p, (u32*)&int32);
- p += 4;
- item->used_size += 4;
- } else {
- *((unsigned char *) p) = size;
- p++;
- item->used_size++;
- }
- memcpy(p, pvalue, size);
- p += size;
- *((char *) p) = (char) 0;
- size++; // null terminator
- item->used_size += size;
- break;
- case BINN_STORAGE_CONTAINER:
- memcpy(p, pvalue, size);
- item->used_size += size;
- break;
- }
-
- item->dirty = TRUE;
-
- return TRUE;
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL binn_save_header(binn *item) {
- unsigned char byte, *p;
- int int32, size;
-
- if (item == NULL) return FALSE;
-
-#ifndef BINN_DISABLE_SMALL_HEADER
-
- p = ((unsigned char *) item->pbuf) + MAX_BINN_HEADER;
- size = item->used_size - MAX_BINN_HEADER + 3; // at least 3 bytes for the header
-
- // write the count
- if (item->count > 127) {
- p -= 4;
- size += 3;
- int32 = item->count | 0x80000000;
- copy_be32((u32*)p, (u32*)&int32);
- } else {
- p--;
- *p = (unsigned char) item->count;
- }
-
- // write the size
- if (size > 127) {
- p -= 4;
- size += 3;
- int32 = size | 0x80000000;
- copy_be32((u32*)p, (u32*)&int32);
- } else {
- p--;
- *p = (unsigned char) size;
- }
-
- // write the type.
- p--;
- *p = (unsigned char) item->type;
-
- // set the values
- item->ptr = p;
- item->size = size;
-
- UNUSED(byte);
-
-#else
-
- p = (unsigned char *) item->pbuf;
-
- // write the type.
- byte = item->type;
- *p = byte; p++;
- // write the size
- int32 = item->used_size | 0x80000000;
- copy_be32((u32*)p, (u32*)&int32);
- p+=4;
- // write the count
- int32 = item->count | 0x80000000;
- copy_be32((u32*)p, (u32*)&int32);
-
- item->ptr = item->pbuf;
- item->size = item->used_size;
-
-#endif
-
- item->dirty = FALSE;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-void APIENTRY binn_free(binn *item) {
-
- if (item == NULL) return;
-
- if ((item->writable) && (item->pre_allocated == FALSE)) {
- free_fn(item->pbuf);
- }
-
- if (item->freefn) item->freefn(item->ptr);
-
- if (item->allocated) {
- free_fn(item);
- } else {
- memset(item, 0, sizeof(binn));
- item->header = BINN_MAGIC;
- }
-
-}
-
-/***************************************************************************/
-// free the binn structure but keeps the binn buffer allocated, returning a pointer to it. use the free function to release the buffer later
-void * APIENTRY binn_release(binn *item) {
- void *data;
-
- if (item == NULL) return NULL;
-
- data = binn_ptr(item);
-
- if (data > item->pbuf) {
- memmove(item->pbuf, data, item->size);
- data = item->pbuf;
- }
-
- if (item->allocated) {
- free_fn(item);
- } else {
- memset(item, 0, sizeof(binn));
- item->header = BINN_MAGIC;
- }
-
- return data;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL IsValidBinnHeader(void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize) {
- unsigned char byte, *p, *plimit=0;
- int int32, type, size, count;
-
- if (pbuf == NULL) return FALSE;
-
- p = (unsigned char *) pbuf;
-
- if (psize && *psize > 0) {
- plimit = p + *psize - 1;
- }
-
- // get the type
- byte = *p; p++;
- if ((byte & BINN_STORAGE_MASK) != BINN_STORAGE_CONTAINER) return FALSE;
- if (byte & BINN_STORAGE_HAS_MORE) return FALSE;
- type = byte;
-
- switch (type) {
- case BINN_LIST:
- case BINN_MAP:
- case BINN_OBJECT:
- break;
- default:
- return FALSE;
- }
-
- // get the size
- if (plimit && p > plimit) return FALSE;
- int32 = *((unsigned char*)p);
- if (int32 & 0x80) {
- if (plimit && p + sizeof(int) - 1 > plimit) return FALSE;
- copy_be32((u32*)&int32, (u32*)p);
- int32 &= 0x7FFFFFFF;
- p+=4;
- } else {
- p++;
- }
- size = int32;
-
- // get the count
- if (plimit && p > plimit) return FALSE;
- int32 = *((unsigned char*)p);
- if (int32 & 0x80) {
- if (plimit && p + sizeof(int) - 1 > plimit) return FALSE;
- copy_be32((u32*)&int32, (u32*)p);
- int32 &= 0x7FFFFFFF;
- p+=4;
- } else {
- p++;
- }
- count = int32;
-
-#if 0
- // get the size
- copy_be32((u32*)&size, (u32*)p);
- size &= 0x7FFFFFFF;
- p+=4;
-
- // get the count
- copy_be32((u32*)&count, (u32*)p);
- count &= 0x7FFFFFFF;
- p+=4;
-#endif
-
- if ((size < MIN_BINN_SIZE) || (count < 0)) return FALSE;
-
- // return the values
- if (ptype) *ptype = type;
- if (pcount) *pcount = count;
- if (psize && *psize==0) *psize = size;
- if (pheadersize) *pheadersize = (int) (p - (unsigned char*)pbuf);
- return TRUE;
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE int binn_buf_type(void *pbuf) {
- int type;
-
- if (!IsValidBinnHeader(pbuf, &type, NULL, NULL, NULL)) return INVALID_BINN;
-
- return type;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE int binn_buf_count(void *pbuf) {
- int nitems;
-
- if (!IsValidBinnHeader(pbuf, NULL, &nitems, NULL, NULL)) return 0;
-
- return nitems;
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE int binn_buf_size(void *pbuf) {
- int size=0;
-
- if (!IsValidBinnHeader(pbuf, NULL, NULL, &size, NULL)) return 0;
-
- return size;
-
-}
-
-/***************************************************************************/
-
-void * APIENTRY binn_ptr(void *ptr) {
- binn *item;
-
- switch (binn_get_ptr_type(ptr)) {
- case BINN_STRUCT:
- item = (binn*) ptr;
- if (item->writable && item->dirty) {
- binn_save_header(item);
- }
- return item->ptr;
- case BINN_BUFFER:
- return ptr;
- default:
- return NULL;
- }
-
-}
-
-/***************************************************************************/
-
-int APIENTRY binn_size(void *ptr) {
- binn *item;
-
- switch (binn_get_ptr_type(ptr)) {
- case BINN_STRUCT:
- item = (binn*) ptr;
- if (item->writable && item->dirty) {
- binn_save_header(item);
- }
- return item->size;
- case BINN_BUFFER:
- return binn_buf_size(ptr);
- default:
- return 0;
- }
-
-}
-
-/***************************************************************************/
-
-int APIENTRY binn_type(void *ptr) {
- binn *item;
-
- switch (binn_get_ptr_type(ptr)) {
- case BINN_STRUCT:
- item = (binn*) ptr;
- return item->type;
- case BINN_BUFFER:
- return binn_buf_type(ptr);
- default:
- return -1;
- }
-
-}
-
-/***************************************************************************/
-
-int APIENTRY binn_count(void *ptr) {
- binn *item;
-
- switch (binn_get_ptr_type(ptr)) {
- case BINN_STRUCT:
- item = (binn*) ptr;
- return item->count;
- case BINN_BUFFER:
- return binn_buf_count(ptr);
- default:
- return -1;
- }
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_is_valid_ex(void *ptr, int *ptype, int *pcount, int *psize) {
- int i, type, count, size, header_size;
- unsigned char *p, *plimit, *base, len;
- void *pbuf;
-
- pbuf = binn_ptr(ptr);
- if (pbuf == NULL) return FALSE;
-
- // is there an informed size?
- if (psize && *psize > 0) {
- size = *psize;
- } else {
- size = 0;
- }
-
- if (!IsValidBinnHeader(pbuf, &type, &count, &size, &header_size)) return FALSE;
-
- // is there an informed size?
- if (psize && *psize > 0) {
- // is it the same as the one in the buffer?
- if (size != *psize) return FALSE;
- }
- // is there an informed count?
- if (pcount && *pcount > 0) {
- // is it the same as the one in the buffer?
- if (count != *pcount) return FALSE;
- }
- // is there an informed type?
- if (ptype && *ptype != 0) {
- // is it the same as the one in the buffer?
- if (type != *ptype) return FALSE;
- }
-
- // it could compare the content size with the size informed on the header
-
- p = (unsigned char *)pbuf;
- base = p;
- plimit = p + size;
-
- p += header_size;
-
- // process all the arguments.
- for (i = 0; i < count; i++) {
- switch (type) {
- case BINN_OBJECT:
- // gets the string size (argument name)
- len = *p;
- p++;
- //if (len == 0) goto Invalid;
- // increment the used space
- p += len;
- break;
- case BINN_MAP:
- // increment the used space
- p += 4;
- break;
- //case BINN_LIST:
- // break;
- }
- // xxx
- p = AdvanceDataPos(p, plimit);
- if ((p == 0) || (p < base)) goto Invalid;
- }
-
- if (ptype && *ptype==0) *ptype = type;
- if (pcount && *pcount==0) *pcount = count;
- if (psize && *psize==0) *psize = size;
- return TRUE;
-
-Invalid:
- return FALSE;
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_is_valid(void *ptr, int *ptype, int *pcount, int *psize) {
-
- if (ptype) *ptype = 0;
- if (pcount) *pcount = 0;
- if (psize) *psize = 0;
-
- return binn_is_valid_ex(ptr, ptype, pcount, psize);
-
-}
-
-/***************************************************************************/
-/*** INTERNAL FUNCTIONS ****************************************************/
-/***************************************************************************/
-
-BINN_PRIVATE BOOL GetValue(unsigned char *p, binn *value) {
- unsigned char byte;
- int data_type, storage_type; //, extra_type;
- int DataSize;
- void *p2;
-
- if (value == NULL) return FALSE;
- memset(value, 0, sizeof(binn));
- value->header = BINN_MAGIC;
- //value->allocated = FALSE; -- already zeroed
- //value->writable = FALSE;
-
- // saves for use with BINN_STORAGE_CONTAINER
- p2 = p;
-
- // read the data type
- byte = *p; p++;
- storage_type = byte & BINN_STORAGE_MASK;
- if (byte & BINN_STORAGE_HAS_MORE) {
- data_type = byte << 8;
- byte = *p; p++;
- data_type |= byte;
- //extra_type = data_type & BINN_TYPE_MASK16;
- } else {
- data_type = byte;
- //extra_type = byte & BINN_TYPE_MASK;
- }
-
- //value->storage_type = storage_type;
- value->type = data_type;
-
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- break;
- case BINN_STORAGE_BYTE:
- value->vuint8 = *((unsigned char *) p);
- value->ptr = p; //value->ptr = &value->vuint8;
- break;
- case BINN_STORAGE_WORD:
- copy_be16((u16*)&value->vint16, (u16*)p);
- value->ptr = &value->vint16;
- break;
- case BINN_STORAGE_DWORD:
- copy_be32((u32*)&value->vint32, (u32*)p);
- value->ptr = &value->vint32;
- break;
- case BINN_STORAGE_QWORD:
- copy_be64((u64*)&value->vint64, (u64*)p);
- value->ptr = &value->vint64;
- break;
- case BINN_STORAGE_BLOB:
- copy_be32((u32*)&value->size, (u32*)p);
- p+=4;
- value->ptr = p;
- break;
- case BINN_STORAGE_CONTAINER:
- value->ptr = p2; // <-- it returns the pointer to the container, not the data
- if (IsValidBinnHeader(p2, NULL, &value->count, &value->size, NULL) == FALSE) return FALSE;
- break;
- case BINN_STORAGE_STRING:
- DataSize = *((unsigned char*)p);
- if (DataSize & 0x80) {
- copy_be32((u32*)&DataSize, (u32*)p);
- DataSize &= 0x7FFFFFFF;
- p+=4;
- } else {
- p++;
- }
- value->size = DataSize;
- value->ptr = p;
- break;
- default:
- return FALSE;
- }
-
- // convert the returned value, if needed
-
- switch (value->type) {
- case BINN_TRUE:
- value->type = BINN_BOOL;
- value->vbool = TRUE;
- value->ptr = &value->vbool;
- break;
- case BINN_FALSE:
- value->type = BINN_BOOL;
- value->vbool = FALSE;
- value->ptr = &value->vbool;
- break;
-#ifdef BINN_EXTENDED
- case BINN_SINGLE_STR:
- value->type = BINN_SINGLE;
- value->vfloat = (float) atof((const char*)value->ptr); // converts from string to double, and then to float
- value->ptr = &value->vfloat;
- break;
- case BINN_DOUBLE_STR:
- value->type = BINN_DOUBLE;
- value->vdouble = atof((const char*)value->ptr); // converts from string to double
- value->ptr = &value->vdouble;
- break;
-#endif
- /*
- case BINN_DECIMAL:
- case BINN_CURRENCYSTR:
- case BINN_DATE:
- case BINN_DATETIME:
- case BINN_TIME:
- */
- }
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-
-// on little-endian devices we store the value so we can return a pointer to integers.
-// it's valid only for single-threaded apps. multi-threaded apps must use the _get_ functions instead.
-
-binn local_value;
-
-BINN_PRIVATE void * store_value(binn *value) {
-
- memcpy(&local_value, value, sizeof(binn));
-
- switch (binn_get_read_storage(value->type)) {
- case BINN_STORAGE_NOBYTES:
- // return a valid pointer
- case BINN_STORAGE_WORD:
- case BINN_STORAGE_DWORD:
- case BINN_STORAGE_QWORD:
- return &local_value.vint32; // returns the pointer to the converted value, from big-endian to little-endian
- }
-
- return value->ptr; // returns from the on stack value to be thread-safe (for list, map, object, string and blob)
-
-}
-
-#endif
-
-/***************************************************************************/
-/*** READ FUNCTIONS ********************************************************/
-/***************************************************************************/
-
-BOOL APIENTRY binn_object_get_value(void *ptr, char *key, binn *value) {
- int type, count, size=0, header_size;
- unsigned char *p;
-
- ptr = binn_ptr(ptr);
- if ((ptr == 0) || (key == 0) || (value == 0)) return FALSE;
-
- // check the header
- if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE;
-
- if (type != BINN_OBJECT) return FALSE;
- if (count == 0) return FALSE;
-
- p = (unsigned char *) ptr;
- p = SearchForKey(p, header_size, size, count, key);
- if (p == FALSE) return FALSE;
-
- return GetValue(p, value);
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_map_get_value(void* ptr, int id, binn *value) {
- int type, count, size=0, header_size;
- unsigned char *p;
-
- ptr = binn_ptr(ptr);
- if ((ptr == 0) || (value == 0)) return FALSE;
-
- // check the header
- if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE;
-
- if (type != BINN_MAP) return FALSE;
- if (count == 0) return FALSE;
-
- p = (unsigned char *) ptr;
- p = SearchForID(p, header_size, size, count, id);
- if (p == FALSE) return FALSE;
-
- return GetValue(p, value);
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_list_get_value(void* ptr, int pos, binn *value) {
- int i, type, count, size=0, header_size;
- unsigned char *p, *plimit, *base;
-
- ptr = binn_ptr(ptr);
- if ((ptr == 0) || (value == 0)) return FALSE;
-
- // check the header
- if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE;
-
- if (type != BINN_LIST) return FALSE;
- if (count == 0) return FALSE;
- if ((pos <= 0) | (pos > count)) return FALSE;
- pos--; // convert from base 1 to base 0
-
- p = (unsigned char *) ptr;
- base = p;
- plimit = p + size;
- p += header_size;
-
- for (i = 0; i < pos; i++) {
- p = AdvanceDataPos(p, plimit);
- if ((p == 0) || (p < base)) return FALSE;
- }
-
- return GetValue(p, value);
-
-}
-
-/***************************************************************************/
-/*** READ PAIR BY POSITION *************************************************/
-/***************************************************************************/
-
-BINN_PRIVATE BOOL binn_read_pair(int expected_type, void *ptr, int pos, int *pid, char *pkey, binn *value) {
- int type, count, size=0, header_size;
- int i, int32, id, counter=0;
- unsigned char *p, *plimit, *base, *key, len;
-
- ptr = binn_ptr(ptr);
-
- // check the header
- if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE;
-
- if ((type != expected_type) || (count == 0) || (pos < 1) || (pos > count)) return FALSE;
-
- p = (unsigned char *) ptr;
- base = p;
- plimit = p + size - 1;
- p += header_size;
-
- for (i = 0; i < count; i++) {
- switch (type) {
- case BINN_MAP:
- copy_be32((u32*)&int32, (u32*)p);
- p += 4;
- if (p > plimit) return FALSE;
- id = int32;
- break;
- case BINN_OBJECT:
- len = *((unsigned char *)p); p++;
- if (p > plimit) return FALSE;
- key = p;
- p += len;
- if (p > plimit) return FALSE;
- break;
- }
- counter++;
- if (counter == pos) goto found;
- //
- p = AdvanceDataPos(p, plimit);
- if ((p == 0) || (p < base)) return FALSE;
- }
-
- return FALSE;
-
-found:
-
- switch (type) {
- case BINN_MAP:
- if (pid) *pid = id;
- break;
- case BINN_OBJECT:
- if (pkey) {
- memcpy(pkey, key, len);
- pkey[len] = 0;
- }
- break;
- }
-
- return GetValue(p, value);
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_map_get_pair(void *ptr, int pos, int *pid, binn *value) {
-
- return binn_read_pair(BINN_MAP, ptr, pos, pid, NULL, value);
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_object_get_pair(void *ptr, int pos, char *pkey, binn *value) {
-
- return binn_read_pair(BINN_OBJECT, ptr, pos, NULL, pkey, value);
-
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_map_pair(void *map, int pos, int *pid) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_read_pair(BINN_MAP, map, pos, pid, NULL, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_object_pair(void *obj, int pos, char *pkey) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_read_pair(BINN_OBJECT, obj, pos, NULL, pkey, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/***************************************************************************/
-/***************************************************************************/
-
-void * APIENTRY binn_map_read_pair(void *ptr, int pos, int *pid, int *ptype, int *psize) {
- binn value;
-
- if (binn_map_get_pair(ptr, pos, pid, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-
-void * APIENTRY binn_object_read_pair(void *ptr, int pos, char *pkey, int *ptype, int *psize) {
- binn value;
-
- if (binn_object_get_pair(ptr, pos, pkey, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-/*** SEQUENTIAL READ FUNCTIONS *********************************************/
-/***************************************************************************/
-
-BOOL APIENTRY binn_iter_init(binn_iter *iter, void *ptr, int expected_type) {
- int type, count, size=0, header_size;
-
- ptr = binn_ptr(ptr);
- if ((ptr == 0) || (iter == 0)) return FALSE;
- memset(iter, 0, sizeof(binn_iter));
-
- // check the header
- if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE;
-
- if (type != expected_type) return FALSE;
- //if (count == 0) return FALSE; -- should not be used
-
- iter->plimit = (unsigned char *)ptr + size - 1;
- iter->pnext = (unsigned char *)ptr + header_size;
- iter->count = count;
- iter->current = 0;
- iter->type = type;
-
- return TRUE;
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_list_next(binn_iter *iter, binn *value) {
- unsigned char *pnow;
-
- if ((iter == 0) || (iter->pnext == 0) || (iter->pnext > iter->plimit) || (iter->current > iter->count) || (iter->type != BINN_LIST)) return FALSE;
-
- iter->current++;
- if (iter->current > iter->count) return FALSE;
-
- pnow = iter->pnext;
- iter->pnext = AdvanceDataPos(pnow, iter->plimit);
- if (iter->pnext != 0 && iter->pnext < pnow) return FALSE;
-
- return GetValue(pnow, value);
-
-}
-
-/***************************************************************************/
-
-BINN_PRIVATE BOOL binn_read_next_pair(int expected_type, binn_iter *iter, int *pid, char *pkey, binn *value) {
- int int32, id;
- unsigned char *p, *key;
- unsigned short len;
-
- if ((iter == 0) || (iter->pnext == 0) || (iter->pnext > iter->plimit) || (iter->current > iter->count) || (iter->type != expected_type)) return FALSE;
-
- iter->current++;
- if (iter->current > iter->count) return FALSE;
-
- p = iter->pnext;
-
- switch (expected_type) {
- case BINN_MAP:
- copy_be32((u32*)&int32, (u32*)p);
- p += 4;
- if (p > iter->plimit) return FALSE;
- id = int32;
- if (pid) *pid = id;
- break;
- case BINN_OBJECT:
- len = *((unsigned char *)p); p++;
- key = p;
- p += len;
- if (p > iter->plimit) return FALSE;
- if (pkey) {
- memcpy(pkey, key, len);
- pkey[len] = 0;
- }
- break;
- }
-
- iter->pnext = AdvanceDataPos(p, iter->plimit);
- if (iter->pnext != 0 && iter->pnext < p) return FALSE;
-
- return GetValue(p, value);
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_map_next(binn_iter *iter, int *pid, binn *value) {
-
- return binn_read_next_pair(BINN_MAP, iter, pid, NULL, value);
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_object_next(binn_iter *iter, char *pkey, binn *value) {
-
- return binn_read_next_pair(BINN_OBJECT, iter, NULL, pkey, value);
-
-}
-
-/***************************************************************************/
-/***************************************************************************/
-
-binn * APIENTRY binn_list_next_value(binn_iter *iter) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_list_next(iter, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_map_next_value(binn_iter *iter, int *pid) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_map_next(iter, pid, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/***************************************************************************/
-
-binn * APIENTRY binn_object_next_value(binn_iter *iter, char *pkey) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_object_next(iter, pkey, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/***************************************************************************/
-/***************************************************************************/
-
-void * APIENTRY binn_list_read_next(binn_iter *iter, int *ptype, int *psize) {
- binn value;
-
- if (binn_list_next(iter, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-
-void * APIENTRY binn_map_read_next(binn_iter *iter, int *pid, int *ptype, int *psize) {
- binn value;
-
- if (binn_map_next(iter, pid, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-
-void * APIENTRY binn_object_read_next(binn_iter *iter, char *pkey, int *ptype, int *psize) {
- binn value;
-
- if (binn_object_next(iter, pkey, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/*************************************************************************************/
-/****** EXTENDED INTERFACE ***********************************************************/
-/****** none of the functions above call the functions below *************************/
-/*************************************************************************************/
-
-int APIENTRY binn_get_write_storage(int type) {
- int storage_type;
-
- switch (type) {
- case BINN_SINGLE_STR:
- case BINN_DOUBLE_STR:
- return BINN_STORAGE_STRING;
-
- case BINN_BOOL:
- return BINN_STORAGE_NOBYTES;
-
- default:
- binn_get_type_info(type, &storage_type, NULL);
- return storage_type;
- }
-
-}
-
-/*************************************************************************************/
-
-int APIENTRY binn_get_read_storage(int type) {
- int storage_type;
-
- switch (type) {
-#ifdef BINN_EXTENDED
- case BINN_SINGLE_STR:
- return BINN_STORAGE_DWORD;
- case BINN_DOUBLE_STR:
- return BINN_STORAGE_QWORD;
-#endif
- case BINN_BOOL:
- case BINN_TRUE:
- case BINN_FALSE:
- return BINN_STORAGE_DWORD;
- default:
- binn_get_type_info(type, &storage_type, NULL);
- return storage_type;
- }
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE BOOL GetWriteConvertedData(int *ptype, void **ppvalue, int *psize) {
- int type;
- float f1;
- double d1;
- char pstr[128];
-
- UNUSED(pstr);
- UNUSED(d1);
- UNUSED(f1);
-
- type = *ptype;
-
- if (*ppvalue == NULL) {
- switch (type) {
- case BINN_NULL:
- case BINN_TRUE:
- case BINN_FALSE:
- break;
- case BINN_STRING:
- case BINN_BLOB:
- if (*psize == 0) break;
- default:
- return FALSE;
- }
- }
-
- switch (type) {
-#ifdef BINN_EXTENDED
- case BINN_SINGLE:
- f1 = **(float**)ppvalue;
- d1 = f1; // convert from float (32bits) to double (64bits)
- type = BINN_SINGLE_STR;
- goto conv_double;
- case BINN_DOUBLE:
- d1 = **(double**)ppvalue;
- type = BINN_DOUBLE_STR;
-conv_double:
- // the '%.17e' is more precise than the '%g'
- snprintf(pstr, 127, "%.17e", d1);
- *ppvalue = pstr;
- *ptype = type;
- break;
-#endif
- case BINN_DECIMAL:
- case BINN_CURRENCYSTR:
- /*
- if (binn_malloc_extptr(128) == NULL) return FALSE;
- snprintf(sptr, 127, "%E", **ppvalue);
- *ppvalue = sptr;
- */
- return TRUE; //! temporary
- break;
-
- case BINN_DATE:
- case BINN_DATETIME:
- case BINN_TIME:
- return TRUE; //! temporary
- break;
-
- case BINN_BOOL:
- if (**((BOOL**)ppvalue) == FALSE) {
- type = BINN_FALSE;
- } else {
- type = BINN_TRUE;
- }
- *ptype = type;
- break;
-
- }
-
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE int type_family(int type) {
-
- switch (type) {
- case BINN_LIST:
- case BINN_MAP:
- case BINN_OBJECT:
- return BINN_FAMILY_BINN;
-
- case BINN_INT8:
- case BINN_INT16:
- case BINN_INT32:
- case BINN_INT64:
- case BINN_UINT8:
- case BINN_UINT16:
- case BINN_UINT32:
- case BINN_UINT64:
- return BINN_FAMILY_INT;
-
- case BINN_FLOAT32:
- case BINN_FLOAT64:
- //case BINN_SINGLE:
- case BINN_SINGLE_STR:
- //case BINN_DOUBLE:
- case BINN_DOUBLE_STR:
- return BINN_FAMILY_FLOAT;
-
- case BINN_STRING:
- case BINN_HTML:
- case BINN_CSS:
- case BINN_XML:
- case BINN_JSON:
- case BINN_JAVASCRIPT:
- return BINN_FAMILY_STRING;
-
- case BINN_BLOB:
- case BINN_JPEG:
- case BINN_GIF:
- case BINN_PNG:
- case BINN_BMP:
- return BINN_FAMILY_BLOB;
-
- case BINN_DECIMAL:
- case BINN_CURRENCY:
- case BINN_DATE:
- case BINN_TIME:
- case BINN_DATETIME:
- return BINN_FAMILY_STRING;
-
- case BINN_BOOL:
- return BINN_FAMILY_BOOL;
-
- case BINN_NULL:
- return BINN_FAMILY_NULL;
-
- default:
- // if it wasn't found
- return BINN_FAMILY_NONE;
- }
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE int int_type(int type) {
-
- switch (type) {
- case BINN_INT8:
- case BINN_INT16:
- case BINN_INT32:
- case BINN_INT64:
- return BINN_SIGNED_INT;
-
- case BINN_UINT8:
- case BINN_UINT16:
- case BINN_UINT32:
- case BINN_UINT64:
- return BINN_UNSIGNED_INT;
-
- default:
- return 0;
- }
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE BOOL copy_raw_value(void *psource, void *pdest, int data_store) {
-
- switch (data_store) {
- case BINN_STORAGE_NOBYTES:
- break;
- case BINN_STORAGE_BYTE:
- *((char *) pdest) = *(char *)psource;
- break;
- case BINN_STORAGE_WORD:
- *((short *) pdest) = *(short *)psource;
- break;
- case BINN_STORAGE_DWORD:
- *((int *) pdest) = *(int *)psource;
- break;
- case BINN_STORAGE_QWORD:
- *((uint64 *) pdest) = *(uint64 *)psource;
- break;
- case BINN_STORAGE_BLOB:
- case BINN_STORAGE_STRING:
- case BINN_STORAGE_CONTAINER:
- *((char **) pdest) = (char *)psource;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE BOOL copy_int_value(void *psource, void *pdest, int source_type, int dest_type) {
- uint64 vuint64; int64 vint64;
-
- switch (source_type) {
- case BINN_INT8:
- vint64 = *(signed char *)psource;
- break;
- case BINN_INT16:
- vint64 = *(short *)psource;
- break;
- case BINN_INT32:
- vint64 = *(int *)psource;
- break;
- case BINN_INT64:
- vint64 = *(int64 *)psource;
- break;
-
- case BINN_UINT8:
- vuint64 = *(unsigned char *)psource;
- break;
- case BINN_UINT16:
- vuint64 = *(unsigned short *)psource;
- break;
- case BINN_UINT32:
- vuint64 = *(unsigned int *)psource;
- break;
- case BINN_UINT64:
- vuint64 = *(uint64 *)psource;
- break;
-
- default:
- return FALSE;
- }
-
-
- // copy from int64 to uint64, if possible
-
- if ((int_type(source_type) == BINN_UNSIGNED_INT) && (int_type(dest_type) == BINN_SIGNED_INT)) {
- if (vuint64 > INT64_MAX) return FALSE;
- vint64 = vuint64;
- } else if ((int_type(source_type) == BINN_SIGNED_INT) && (int_type(dest_type) == BINN_UNSIGNED_INT)) {
- if (vint64 < 0) return FALSE;
- vuint64 = vint64;
- }
-
-
- switch (dest_type) {
- case BINN_INT8:
- if ((vint64 < INT8_MIN) || (vint64 > INT8_MAX)) return FALSE;
- *(signed char *)pdest = (signed char) vint64;
- break;
- case BINN_INT16:
- if ((vint64 < INT16_MIN) || (vint64 > INT16_MAX)) return FALSE;
- *(short *)pdest = (short) vint64;
- break;
- case BINN_INT32:
- if ((vint64 < INT32_MIN) || (vint64 > INT32_MAX)) return FALSE;
- *(int *)pdest = (int) vint64;
- break;
- case BINN_INT64:
- *(int64 *)pdest = vint64;
- break;
-
- case BINN_UINT8:
- if (vuint64 > UINT8_MAX) return FALSE;
- *(unsigned char *)pdest = (unsigned char) vuint64;
- break;
- case BINN_UINT16:
- if (vuint64 > UINT16_MAX) return FALSE;
- *(unsigned short *)pdest = (unsigned short) vuint64;
- break;
- case BINN_UINT32:
- if (vuint64 > UINT32_MAX) return FALSE;
- *(unsigned int *)pdest = (unsigned int) vuint64;
- break;
- case BINN_UINT64:
- *(uint64 *)pdest = vuint64;
- break;
-
- default:
- return FALSE;
- }
-
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE BOOL copy_float_value(void *psource, void *pdest, int source_type, int dest_type) {
-
- switch (source_type) {
- case BINN_FLOAT32:
- *(double *)pdest = *(float *)psource;
- break;
- case BINN_FLOAT64:
- *(float *)pdest = (float) *(double *)psource;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE void zero_value(void *pvalue, int type) {
- //int size=0;
-
- switch (binn_get_read_storage(type)) {
- case BINN_STORAGE_NOBYTES:
- break;
- case BINN_STORAGE_BYTE:
- *((char *) pvalue) = 0;
- //size=1;
- break;
- case BINN_STORAGE_WORD:
- *((short *) pvalue) = 0;
- //size=2;
- break;
- case BINN_STORAGE_DWORD:
- *((int *) pvalue) = 0;
- //size=4;
- break;
- case BINN_STORAGE_QWORD:
- *((uint64 *) pvalue) = 0;
- //size=8;
- break;
- case BINN_STORAGE_BLOB:
- case BINN_STORAGE_STRING:
- case BINN_STORAGE_CONTAINER:
- *(char **)pvalue = NULL;
- break;
- }
-
- //if (size>0) memset(pvalue, 0, size);
-
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE BOOL copy_value(void *psource, void *pdest, int source_type, int dest_type, int data_store) {
-
- if (type_family(source_type) != type_family(dest_type)) return FALSE;
-
- if ((type_family(source_type) == BINN_FAMILY_INT) && (source_type != dest_type)) {
- return copy_int_value(psource, pdest, source_type, dest_type);
- } else if ((type_family(source_type) == BINN_FAMILY_FLOAT) && (source_type != dest_type)) {
- return copy_float_value(psource, pdest, source_type, dest_type);
- } else {
- return copy_raw_value(psource, pdest, data_store);
- }
-
-}
-
-/*************************************************************************************/
-/*** WRITE FUNCTIONS *****************************************************************/
-/*************************************************************************************/
-
-BOOL APIENTRY binn_list_add(binn *list, int type, void *pvalue, int size) {
-
- if (GetWriteConvertedData(&type, &pvalue, &size) == FALSE) return FALSE;
-
- return binn_list_add_raw(list, type, pvalue, size);
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_map_set(binn *map, int id, int type, void *pvalue, int size) {
-
- if (GetWriteConvertedData(&type, &pvalue, &size) == FALSE) return FALSE;
-
- return binn_map_set_raw(map, id, type, pvalue, size);
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_object_set(binn *obj, char *key, int type, void *pvalue, int size) {
-
- if (GetWriteConvertedData(&type, &pvalue, &size) == FALSE) return FALSE;
-
- return binn_object_set_raw(obj, key, type, pvalue, size);
-
-}
-
-/*************************************************************************************/
-
-// this function is used by the wrappers
-BOOL APIENTRY binn_add_value(binn *item, int binn_type, int id, char *name, int type, void *pvalue, int size) {
-
- switch (binn_type) {
- case BINN_LIST:
- return binn_list_add(item, type, pvalue, size);
- case BINN_MAP:
- return binn_map_set(item, id, type, pvalue, size);
- case BINN_OBJECT:
- return binn_object_set(item, name, type, pvalue, size);
- default:
- return FALSE;
- }
-
-}
-
-/*************************************************************************************/
-/*************************************************************************************/
-
-BOOL APIENTRY binn_list_add_new(binn *list, binn *value) {
- BOOL retval;
-
- retval = binn_list_add_value(list, value);
- if (value) free_fn(value);
- return retval;
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_map_set_new(binn *map, int id, binn *value) {
- BOOL retval;
-
- retval = binn_map_set_value(map, id, value);
- if (value) free_fn(value);
- return retval;
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_object_set_new(binn *obj, char *key, binn *value) {
- BOOL retval;
-
- retval = binn_object_set_value(obj, key, value);
- if (value) free_fn(value);
- return retval;
-
-}
-
-/*************************************************************************************/
-/*** READ FUNCTIONS ******************************************************************/
-/*************************************************************************************/
-
-binn * APIENTRY binn_list_value(void *ptr, int pos) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_list_get_value(ptr, pos, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/*************************************************************************************/
-
-binn * APIENTRY binn_map_value(void *ptr, int id) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_map_get_value(ptr, id, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/*************************************************************************************/
-
-binn * APIENTRY binn_object_value(void *ptr, char *key) {
- binn *value;
-
- value = (binn *) binn_malloc(sizeof(binn));
-
- if (binn_object_get_value(ptr, key, value) == FALSE) {
- free_fn(value);
- return NULL;
- }
-
- value->allocated = TRUE;
- return value;
-
-}
-
-/***************************************************************************/
-/***************************************************************************/
-
-void * APIENTRY binn_list_read(void *list, int pos, int *ptype, int *psize) {
- binn value;
-
- if (binn_list_get_value(list, pos, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-
-void * APIENTRY binn_map_read(void *map, int id, int *ptype, int *psize) {
- binn value;
-
- if (binn_map_get_value(map, id, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-
-void * APIENTRY binn_object_read(void *obj, char *key, int *ptype, int *psize) {
- binn value;
-
- if (binn_object_get_value(obj, key, &value) == FALSE) return NULL;
- if (ptype) *ptype = value.type;
- if (psize) *psize = value.size;
-#if BYTE_ORDER == LITTLE_ENDIAN
- return store_value(&value);
-#else
- return value.ptr;
-#endif
-
-}
-
-/***************************************************************************/
-/***************************************************************************/
-
-BOOL APIENTRY binn_list_get(void *ptr, int pos, int type, void *pvalue, int *psize) {
- binn value;
- int storage_type;
-
- storage_type = binn_get_read_storage(type);
- if ((storage_type != BINN_STORAGE_NOBYTES) && (pvalue == NULL)) return FALSE;
-
- zero_value(pvalue, type);
-
- if (binn_list_get_value(ptr, pos, &value) == FALSE) return FALSE;
-
- if (copy_value(value.ptr, pvalue, value.type, type, storage_type) == FALSE) return FALSE;
-
- if (psize) *psize = value.size;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-BOOL APIENTRY binn_map_get(void *ptr, int id, int type, void *pvalue, int *psize) {
- binn value;
- int storage_type;
-
- storage_type = binn_get_read_storage(type);
- if ((storage_type != BINN_STORAGE_NOBYTES) && (pvalue == NULL)) return FALSE;
-
- zero_value(pvalue, type);
-
- if (binn_map_get_value(ptr, id, &value) == FALSE) return FALSE;
-
- if (copy_value(value.ptr, pvalue, value.type, type, storage_type) == FALSE) return FALSE;
-
- if (psize) *psize = value.size;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-
-// if (binn_object_get(obj, "multiplier", BINN_INT32, &multiplier, NULL) == FALSE) xxx;
-
-BOOL APIENTRY binn_object_get(void *ptr, char *key, int type, void *pvalue, int *psize) {
- binn value;
- int storage_type;
-
- storage_type = binn_get_read_storage(type);
- if ((storage_type != BINN_STORAGE_NOBYTES) && (pvalue == NULL)) return FALSE;
-
- zero_value(pvalue, type);
-
- if (binn_object_get_value(ptr, key, &value) == FALSE) return FALSE;
-
- if (copy_value(value.ptr, pvalue, value.type, type, storage_type) == FALSE) return FALSE;
-
- if (psize) *psize = value.size;
-
- return TRUE;
-
-}
-
-/***************************************************************************/
-/***************************************************************************/
-
-// these functions below may not be implemented as inline functions, because
-// they use a lot of space, even for the variable. so they will be exported.
-
-// but what about using as static?
-// is there any problem with wrappers? can these wrappers implement these functions using the header?
-// if as static, will they be present even on modules that don't use the functions?
-
-signed char APIENTRY binn_list_int8(void *list, int pos) {
- signed char value;
-
- binn_list_get(list, pos, BINN_INT8, &value, NULL);
-
- return value;
-}
-
-short APIENTRY binn_list_int16(void *list, int pos) {
- short value;
-
- binn_list_get(list, pos, BINN_INT16, &value, NULL);
-
- return value;
-}
-
-int APIENTRY binn_list_int32(void *list, int pos) {
- int value;
-
- binn_list_get(list, pos, BINN_INT32, &value, NULL);
-
- return value;
-}
-
-int64 APIENTRY binn_list_int64(void *list, int pos) {
- int64 value;
-
- binn_list_get(list, pos, BINN_INT64, &value, NULL);
-
- return value;
-}
-
-unsigned char APIENTRY binn_list_uint8(void *list, int pos) {
- unsigned char value;
-
- binn_list_get(list, pos, BINN_UINT8, &value, NULL);
-
- return value;
-}
-
-unsigned short APIENTRY binn_list_uint16(void *list, int pos) {
- unsigned short value;
-
- binn_list_get(list, pos, BINN_UINT16, &value, NULL);
-
- return value;
-}
-
-unsigned int APIENTRY binn_list_uint32(void *list, int pos) {
- unsigned int value;
-
- binn_list_get(list, pos, BINN_UINT32, &value, NULL);
-
- return value;
-}
-
-uint64 APIENTRY binn_list_uint64(void *list, int pos) {
- uint64 value;
-
- binn_list_get(list, pos, BINN_UINT64, &value, NULL);
-
- return value;
-}
-
-float APIENTRY binn_list_float(void *list, int pos) {
- float value;
-
- binn_list_get(list, pos, BINN_FLOAT32, &value, NULL);
-
- return value;
-}
-
-double APIENTRY binn_list_double(void *list, int pos) {
- double value;
-
- binn_list_get(list, pos, BINN_FLOAT64, &value, NULL);
-
- return value;
-}
-
-BOOL APIENTRY binn_list_bool(void *list, int pos) {
- BOOL value;
-
- binn_list_get(list, pos, BINN_BOOL, &value, NULL);
-
- return value;
-}
-
-BOOL APIENTRY binn_list_null(void *list, int pos) {
-
- return binn_list_get(list, pos, BINN_NULL, NULL, NULL);
-
-}
-
-char * APIENTRY binn_list_str(void *list, int pos) {
- char *value;
-
- binn_list_get(list, pos, BINN_STRING, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_list_blob(void *list, int pos, int *psize) {
- void *value;
-
- binn_list_get(list, pos, BINN_BLOB, &value, psize);
-
- return value;
-}
-
-void * APIENTRY binn_list_list(void *list, int pos) {
- void *value;
-
- binn_list_get(list, pos, BINN_LIST, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_list_map(void *list, int pos) {
- void *value;
-
- binn_list_get(list, pos, BINN_MAP, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_list_object(void *list, int pos) {
- void *value;
-
- binn_list_get(list, pos, BINN_OBJECT, &value, NULL);
-
- return value;
-}
-
-/***************************************************************************/
-
-signed char APIENTRY binn_map_int8(void *map, int id) {
- signed char value;
-
- binn_map_get(map, id, BINN_INT8, &value, NULL);
-
- return value;
-}
-
-short APIENTRY binn_map_int16(void *map, int id) {
- short value;
-
- binn_map_get(map, id, BINN_INT16, &value, NULL);
-
- return value;
-}
-
-int APIENTRY binn_map_int32(void *map, int id) {
- int value;
-
- binn_map_get(map, id, BINN_INT32, &value, NULL);
-
- return value;
-}
-
-int64 APIENTRY binn_map_int64(void *map, int id) {
- int64 value;
-
- binn_map_get(map, id, BINN_INT64, &value, NULL);
-
- return value;
-}
-
-unsigned char APIENTRY binn_map_uint8(void *map, int id) {
- unsigned char value;
-
- binn_map_get(map, id, BINN_UINT8, &value, NULL);
-
- return value;
-}
-
-unsigned short APIENTRY binn_map_uint16(void *map, int id) {
- unsigned short value;
-
- binn_map_get(map, id, BINN_UINT16, &value, NULL);
-
- return value;
-}
-
-unsigned int APIENTRY binn_map_uint32(void *map, int id) {
- unsigned int value;
-
- binn_map_get(map, id, BINN_UINT32, &value, NULL);
-
- return value;
-}
-
-uint64 APIENTRY binn_map_uint64(void *map, int id) {
- uint64 value;
-
- binn_map_get(map, id, BINN_UINT64, &value, NULL);
-
- return value;
-}
-
-float APIENTRY binn_map_float(void *map, int id) {
- float value;
-
- binn_map_get(map, id, BINN_FLOAT32, &value, NULL);
-
- return value;
-}
-
-double APIENTRY binn_map_double(void *map, int id) {
- double value;
-
- binn_map_get(map, id, BINN_FLOAT64, &value, NULL);
-
- return value;
-}
-
-BOOL APIENTRY binn_map_bool(void *map, int id) {
- BOOL value;
-
- binn_map_get(map, id, BINN_BOOL, &value, NULL);
-
- return value;
-}
-
-BOOL APIENTRY binn_map_null(void *map, int id) {
-
- return binn_map_get(map, id, BINN_NULL, NULL, NULL);
-
-}
-
-char * APIENTRY binn_map_str(void *map, int id) {
- char *value;
-
- binn_map_get(map, id, BINN_STRING, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_map_blob(void *map, int id, int *psize) {
- void *value;
-
- binn_map_get(map, id, BINN_BLOB, &value, psize);
-
- return value;
-}
-
-void * APIENTRY binn_map_list(void *map, int id) {
- void *value;
-
- binn_map_get(map, id, BINN_LIST, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_map_map(void *map, int id) {
- void *value;
-
- binn_map_get(map, id, BINN_MAP, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_map_object(void *map, int id) {
- void *value;
-
- binn_map_get(map, id, BINN_OBJECT, &value, NULL);
-
- return value;
-}
-
-/***************************************************************************/
-
-signed char APIENTRY binn_object_int8(void *obj, char *key) {
- signed char value;
-
- binn_object_get(obj, key, BINN_INT8, &value, NULL);
-
- return value;
-}
-
-short APIENTRY binn_object_int16(void *obj, char *key) {
- short value;
-
- binn_object_get(obj, key, BINN_INT16, &value, NULL);
-
- return value;
-}
-
-int APIENTRY binn_object_int32(void *obj, char *key) {
- int value;
-
- binn_object_get(obj, key, BINN_INT32, &value, NULL);
-
- return value;
-}
-
-int64 APIENTRY binn_object_int64(void *obj, char *key) {
- int64 value;
-
- binn_object_get(obj, key, BINN_INT64, &value, NULL);
-
- return value;
-}
-
-unsigned char APIENTRY binn_object_uint8(void *obj, char *key) {
- unsigned char value;
-
- binn_object_get(obj, key, BINN_UINT8, &value, NULL);
-
- return value;
-}
-
-unsigned short APIENTRY binn_object_uint16(void *obj, char *key) {
- unsigned short value;
-
- binn_object_get(obj, key, BINN_UINT16, &value, NULL);
-
- return value;
-}
-
-unsigned int APIENTRY binn_object_uint32(void *obj, char *key) {
- unsigned int value;
-
- binn_object_get(obj, key, BINN_UINT32, &value, NULL);
-
- return value;
-}
-
-uint64 APIENTRY binn_object_uint64(void *obj, char *key) {
- uint64 value;
-
- binn_object_get(obj, key, BINN_UINT64, &value, NULL);
-
- return value;
-}
-
-float APIENTRY binn_object_float(void *obj, char *key) {
- float value;
-
- binn_object_get(obj, key, BINN_FLOAT32, &value, NULL);
-
- return value;
-}
-
-double APIENTRY binn_object_double(void *obj, char *key) {
- double value;
-
- binn_object_get(obj, key, BINN_FLOAT64, &value, NULL);
-
- return value;
-}
-
-BOOL APIENTRY binn_object_bool(void *obj, char *key) {
- BOOL value;
-
- binn_object_get(obj, key, BINN_BOOL, &value, NULL);
-
- return value;
-}
-
-BOOL APIENTRY binn_object_null(void *obj, char *key) {
-
- return binn_object_get(obj, key, BINN_NULL, NULL, NULL);
-
-}
-
-char * APIENTRY binn_object_str(void *obj, char *key) {
- char *value;
-
- binn_object_get(obj, key, BINN_STRING, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_object_blob(void *obj, char *key, int *psize) {
- void *value;
-
- binn_object_get(obj, key, BINN_BLOB, &value, psize);
-
- return value;
-}
-
-void * APIENTRY binn_object_list(void *obj, char *key) {
- void *value;
-
- binn_object_get(obj, key, BINN_LIST, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_object_map(void *obj, char *key) {
- void *value;
-
- binn_object_get(obj, key, BINN_MAP, &value, NULL);
-
- return value;
-}
-
-void * APIENTRY binn_object_object(void *obj, char *key) {
- void *value;
-
- binn_object_get(obj, key, BINN_OBJECT, &value, NULL);
-
- return value;
-}
-
-/*************************************************************************************/
-/*************************************************************************************/
-
-BINN_PRIVATE binn * binn_alloc_item() {
- binn *item;
- item = (binn *) binn_malloc(sizeof(binn));
- if (item) {
- memset(item, 0, sizeof(binn));
- item->header = BINN_MAGIC;
- item->allocated = TRUE;
- //item->writable = FALSE; -- already zeroed
- }
- return item;
-}
-
-/*************************************************************************************/
-
-binn * APIENTRY binn_value(int type, void *pvalue, int size, binn_mem_free freefn) {
- int storage_type;
- binn *item = binn_alloc_item();
- if (item) {
- item->type = type;
- binn_get_type_info(type, &storage_type, NULL);
- switch (storage_type) {
- case BINN_STORAGE_NOBYTES:
- break;
- case BINN_STORAGE_STRING:
- if (size == 0) size = strlen((char*)pvalue) + 1;
- case BINN_STORAGE_BLOB:
- case BINN_STORAGE_CONTAINER:
- if (freefn == BINN_TRANSIENT) {
- item->ptr = binn_memdup(pvalue, size);
- if (item->ptr == NULL) {
- free_fn(item);
- return NULL;
- }
- item->freefn = free_fn;
- if (storage_type == BINN_STORAGE_STRING) size--;
- } else {
- item->ptr = pvalue;
- item->freefn = freefn;
- }
- item->size = size;
- break;
- default:
- item->ptr = &item->vint32;
- copy_raw_value(pvalue, item->ptr, storage_type);
- }
- }
- return item;
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_set_string(binn *item, char *str, binn_mem_free pfree) {
-
- if (item == NULL || str == NULL) return FALSE;
-
- if (pfree == BINN_TRANSIENT) {
- item->ptr = binn_memdup(str, strlen(str) + 1);
- if (item->ptr == NULL) return FALSE;
- item->freefn = free_fn;
- } else {
- item->ptr = str;
- item->freefn = pfree;
- }
-
- item->type = BINN_STRING;
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_set_blob(binn *item, void *ptr, int size, binn_mem_free pfree) {
-
- if (item == NULL || ptr == NULL) return FALSE;
-
- if (pfree == BINN_TRANSIENT) {
- item->ptr = binn_memdup(ptr, size);
- if (item->ptr == NULL) return FALSE;
- item->freefn = free_fn;
- } else {
- item->ptr = ptr;
- item->freefn = pfree;
- }
-
- item->type = BINN_BLOB;
- item->size = size;
- return TRUE;
-
-}
-
-/*************************************************************************************/
-/*** READ CONVERTED VALUE ************************************************************/
-/*************************************************************************************/
-
-#ifdef _MSC_VER
-#define atoi64 _atoi64
-#else
-int64 atoi64(char *str) {
- int64 retval;
- int is_negative=0;
-
- if (*str == '-') {
- is_negative = 1;
- str++;
- }
- retval = 0;
- for (; *str; str++) {
- retval = 10 * retval + (*str - '0');
- }
- if (is_negative) retval *= -1;
- return retval;
-}
-#endif
-
-/*****************************************************************************/
-
-BINN_PRIVATE BOOL is_integer(char *p) {
- BOOL retval;
-
- if (p == NULL) return FALSE;
- if (*p == '-') p++;
- if (*p == 0) return FALSE;
-
- retval = TRUE;
-
- for (; *p; p++) {
- if ( (*p < '0') || (*p > '9') ) {
- retval = FALSE;
- }
- }
-
- return retval;
-}
-
-/*****************************************************************************/
-
-BINN_PRIVATE BOOL is_float(char *p) {
- BOOL retval, number_found=FALSE;
-
- if (p == NULL) return FALSE;
- if (*p == '-') p++;
- if (*p == 0) return FALSE;
-
- retval = TRUE;
-
- for (; *p; p++) {
- if ((*p == '.') || (*p == ',')) {
- if (!number_found) retval = FALSE;
- } else if ( (*p >= '0') && (*p <= '9') ) {
- number_found = TRUE;
- } else {
- return FALSE;
- }
- }
-
- return retval;
-}
-
-/*************************************************************************************/
-
-BINN_PRIVATE BOOL is_bool_str(char *str, BOOL *pbool) {
- int64 vint;
- double vdouble;
-
- if (str == NULL || pbool == NULL) return FALSE;
-
- if (stricmp(str, "true") == 0) goto loc_true;
- if (stricmp(str, "yes") == 0) goto loc_true;
- if (stricmp(str, "on") == 0) goto loc_true;
- //if (stricmp(str, "1") == 0) goto loc_true;
-
- if (stricmp(str, "false") == 0) goto loc_false;
- if (stricmp(str, "no") == 0) goto loc_false;
- if (stricmp(str, "off") == 0) goto loc_false;
- //if (stricmp(str, "0") == 0) goto loc_false;
-
- if (is_integer(str)) {
- vint = atoi64(str);
- *pbool = (vint != 0) ? TRUE : FALSE;
- return TRUE;
- } else if (is_float(str)) {
- vdouble = atof(str);
- *pbool = (vdouble != 0) ? TRUE : FALSE;
- return TRUE;
- }
-
- return FALSE;
-
-loc_true:
- *pbool = TRUE;
- return TRUE;
-
-loc_false:
- *pbool = FALSE;
- return TRUE;
-
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_get_int32(binn *value, int *pint) {
-
- if (value == NULL || pint == NULL) return FALSE;
-
- if (type_family(value->type) == BINN_FAMILY_INT) {
- return copy_int_value(value->ptr, pint, value->type, BINN_INT32);
- }
-
- switch (value->type) {
- case BINN_FLOAT:
- if ((value->vfloat < INT32_MIN) || (value->vfloat > INT32_MAX)) return FALSE;
- *pint = round(value->vfloat);
- break;
- case BINN_DOUBLE:
- if ((value->vdouble < INT32_MIN) || (value->vdouble > INT32_MAX)) return FALSE;
- *pint = round(value->vdouble);
- break;
- case BINN_STRING:
- if (is_integer((char*)value->ptr))
- *pint = atoi((char*)value->ptr);
- else if (is_float((char*)value->ptr))
- *pint = round(atof((char*)value->ptr));
- else
- return FALSE;
- break;
- case BINN_BOOL:
- *pint = value->vbool;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_get_int64(binn *value, int64 *pint) {
-
- if (value == NULL || pint == NULL) return FALSE;
-
- if (type_family(value->type) == BINN_FAMILY_INT) {
- return copy_int_value(value->ptr, pint, value->type, BINN_INT64);
- }
-
- switch (value->type) {
- case BINN_FLOAT:
- if ((value->vfloat < INT64_MIN) || (value->vfloat > INT64_MAX)) return FALSE;
- *pint = round(value->vfloat);
- break;
- case BINN_DOUBLE:
- if ((value->vdouble < INT64_MIN) || (value->vdouble > INT64_MAX)) return FALSE;
- *pint = round(value->vdouble);
- break;
- case BINN_STRING:
- if (is_integer((char*)value->ptr))
- *pint = atoi64((char*)value->ptr);
- else if (is_float((char*)value->ptr))
- *pint = round(atof((char*)value->ptr));
- else
- return FALSE;
- break;
- case BINN_BOOL:
- *pint = value->vbool;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_get_double(binn *value, double *pfloat) {
- int64 vint;
-
- if (value == NULL || pfloat == NULL) return FALSE;
-
- if (type_family(value->type) == BINN_FAMILY_INT) {
- if (copy_int_value(value->ptr, &vint, value->type, BINN_INT64) == FALSE) return FALSE;
- *pfloat = (double) vint;
- return TRUE;
- }
-
- switch (value->type) {
- case BINN_FLOAT:
- *pfloat = value->vfloat;
- break;
- case BINN_DOUBLE:
- *pfloat = value->vdouble;
- break;
- case BINN_STRING:
- if (is_integer((char*)value->ptr))
- *pfloat = (double) atoi64((char*)value->ptr);
- else if (is_float((char*)value->ptr))
- *pfloat = atof((char*)value->ptr);
- else
- return FALSE;
- break;
- case BINN_BOOL:
- *pfloat = value->vbool;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*************************************************************************************/
-
-BOOL APIENTRY binn_get_bool(binn *value, BOOL *pbool) {
- int64 vint;
-
- if (value == NULL || pbool == NULL) return FALSE;
-
- if (type_family(value->type) == BINN_FAMILY_INT) {
- if (copy_int_value(value->ptr, &vint, value->type, BINN_INT64) == FALSE) return FALSE;
- *pbool = (vint != 0) ? TRUE : FALSE;
- return TRUE;
- }
-
- switch (value->type) {
- case BINN_BOOL:
- *pbool = value->vbool;
- break;
- case BINN_FLOAT:
- *pbool = (value->vfloat != 0) ? TRUE : FALSE;
- break;
- case BINN_DOUBLE:
- *pbool = (value->vdouble != 0) ? TRUE : FALSE;
- break;
- case BINN_STRING:
- return is_bool_str((char*)value->ptr, pbool);
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*************************************************************************************/
-
-char * APIENTRY binn_get_str(binn *value) {
- int64 vint;
- char buf[128];
-
- if (value == NULL) return NULL;
-
- if (type_family(value->type) == BINN_FAMILY_INT) {
- if (copy_int_value(value->ptr, &vint, value->type, BINN_INT64) == FALSE) return NULL;
- sprintf(buf, "%" INT64_FORMAT, vint);
- goto loc_convert_value;
- }
-
- switch (value->type) {
- case BINN_FLOAT:
- value->vdouble = value->vfloat;
- case BINN_DOUBLE:
- sprintf(buf, "%g", value->vdouble);
- goto loc_convert_value;
- case BINN_STRING:
- return (char*) value->ptr;
- case BINN_BOOL:
- if (value->vbool)
- strcpy(buf, "true");
- else
- strcpy(buf, "false");
- goto loc_convert_value;
- }
-
- return NULL;
-
-loc_convert_value:
-
- //value->vint64 = 0;
- value->ptr = strdup(buf);
- if (value->ptr == NULL) return NULL;
- value->freefn = free;
- value->type = BINN_STRING;
- return (char*) value->ptr;
-
-}
-
-/*************************************************************************************/
-/*** GENERAL FUNCTIONS ***************************************************************/
-/*************************************************************************************/
-
-BOOL APIENTRY binn_is_container(binn *item) {
-
- if (item == NULL) return FALSE;
-
- switch (item->type) {
- case BINN_LIST:
- case BINN_MAP:
- case BINN_OBJECT:
- return TRUE;
- default:
- return FALSE;
- }
-
-}
-
-/*************************************************************************************/
diff --git a/src/lib/capnp-c/capn-malloc.cc b/src/lib/capnp-c/capn-malloc.cc
deleted file mode 100644
index 79f08c8..0000000
--- a/src/lib/capnp-c/capn-malloc.cc
+++ /dev/null
@@ -1,424 +0,0 @@
-/* vim: set sw=8 ts=8 sts=8 noet: */
-/* capn-malloc.c
- *
- * Copyright (C) 2013 James McKaskill
- * Copyright (C) 2014 Steve Dee
- *
- * This software may be modified and distributed under the terms
- * of the MIT license. See the LICENSE file for details.
- */
-
-#ifdef __GNUC__
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#endif
-
-#include "capnp_c.h"
-#include "capnp_priv.h"
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <errno.h>
-
-#ifdef MULTIPASS_TRACE_MALLOC
-#include "lib/mpmalloc.h"
-#else
-#define mpcalloc calloc
-#define mpfree free
-#endif
-
-/*
- * 8 byte alignment is required for struct capn_segment.
- * This struct check_segment_alignment verifies this at compile time.
- *
- * Unless capn_segment is defined with 8 byte alignment, check_segment_alignment
- * fails to compile in x86 mode (or on another CPU with 32-bit pointers),
- * as (sizeof(struct capn_segment)&7) -> (44 & 7) evaluates to 4.
- * It compiles in x64 mode (or on another CPU with 64-bit pointers),
- * as (sizeof(struct capn_segment)&7) -> (80 & 7) evaluates to 0.
- */
-struct check_segment_alignment {
- unsigned int foo : (sizeof(struct capn_segment)&7) ? -1 : 1;
-};
-
-static struct capn_segment *create(void *u, uint32_t id, int sz) {
- struct capn_segment *s;
- sz += sizeof(*s);
-#if 0
- if (sz < 1024) {
- sz = 1024;
- } else {
- sz = (sz + 1023) & ~1023;
- }
-#else
- if (sz < 4096) {
- sz = 4096;
- } else {
- sz = (sz + 4095) & ~4095;
- }
-#endif
- s = (struct capn_segment*) mpcalloc(1, sz);
- s->data = (char*) (s+1);
- s->cap = sz - sizeof(*s);
- s->user = s;
- return s;
-}
-
-static struct capn_segment *create_local(void *u, int sz) {
- return create(u, 0, sz);
-}
-
-void capn_init_malloc(struct capn *c) {
- memset(c, 0, sizeof(*c));
- c->create = &create;
- c->create_local = &create_local;
-}
-
-void capn_free(struct capn *c) {
- struct capn_segment *s = c->seglist;
- while (s != NULL) {
- struct capn_segment *n = s->next;
- mpfree(s->user);
- s = n;
- }
- capn_reset_copy(c);
-}
-
-void capn_reset_copy(struct capn *c) {
- struct capn_segment *s = c->copylist;
- while (s != NULL) {
- struct capn_segment *n = s->next;
- mpfree(s->user);
- s = n;
- }
- c->copy = NULL;
- c->copylist = NULL;
-}
-
-#define ZBUF_SZ 4096
-
-static int read_fp(void *p, size_t sz, FILE *f, struct capn_stream *z, uint8_t* zbuf, int packed) {
- if (f && packed) {
- z->next_out = (uint8_t*) p;
- z->avail_out = sz;
-
- while (z->avail_out && capn_inflate(z) == CAPN_NEED_MORE) {
- int r;
- memmove(zbuf, z->next_in, z->avail_in);
- r = fread(zbuf+z->avail_in, 1, ZBUF_SZ - z->avail_in, f);
- if (r <= 0)
- return -1;
- z->avail_in += r;
- }
- return 0;
-
- } else if (f && !packed) {
- return fread(p, sz, 1, f) != 1;
-
- } else if (packed) {
- z->next_out = (uint8_t*) p;
- z->avail_out = sz;
- return capn_inflate(z) != 0;
-
- } else {
- if (z->avail_in < sz)
- return -1;
- memcpy(p, z->next_in, sz);
- z->next_in += sz;
- z->avail_in -= sz;
- return 0;
- }
-}
-
-static int init_fp(struct capn *c, FILE *f, struct capn_stream *z, int packed) {
- /*
- * Initialize 'c' from the contents of 'f', assuming the message has been
- * serialized with the standard framing format. From https://capnproto.org/encoding.html:
- *
- * When transmitting over a stream, the following should be sent. All integers are unsigned and little-endian.
- * (4 bytes) The number of segments, minus one (since there is always at least one segment).
- * (N * 4 bytes) The size of each segment, in words.
- * (0 or 4 bytes) Padding up to the next word boundary.
- * The content of each segment, in order.
- */
-
- struct capn_segment *s = NULL;
- uint32_t i, segnum, total = 0;
- uint32_t hdr[1024];
- uint8_t zbuf[ZBUF_SZ];
- char *data = NULL;
-
- capn_init_malloc(c);
-
- /* Read the first four bytes to know how many headers we have */
- if (read_fp(&segnum, 4, f, z, zbuf, packed))
- goto err;
-
- segnum = capn_flip32(segnum);
- if (segnum > 1023)
- goto err;
- segnum++; /* The wire encoding was zero-based */
-
- /* Read the header list */
- if (read_fp(hdr, 8 * (segnum/2) + 4, f, z, zbuf, packed))
- goto err;
-
- for (i = 0; i < segnum; i++) {
- uint32_t n = capn_flip32(hdr[i]);
- if (n > INT_MAX/8 || n > UINT32_MAX/8 || UINT32_MAX - total < n*8)
- goto err;
- hdr[i] = n*8;
- total += hdr[i];
- }
-
- /* Allocate space for the data and the capn_segment structs */
- s = (struct capn_segment*) mpcalloc(1, total + (sizeof(*s) * segnum));
- if (!s)
- goto err;
-
- /* Now read the data and setup the capn_segment structs */
- data = (char*) (s+segnum);
- if (read_fp(data, total, f, z, zbuf, packed))
- goto err;
-
- for (i = 0; i < segnum; i++) {
- s[i].len = s[i].cap = hdr[i];
- s[i].data = data;
- data += s[i].len;
- capn_append_segment(c, &s[i]);
- }
-
- /* Set the entire region to be freed on the last segment */
- s[segnum-1].user = s;
-
- return 0;
-
-err:
- memset(c, 0, sizeof(*c));
- mpfree(s);
- return -1;
-}
-
-int capn_init_fp(struct capn *c, FILE *f, int packed) {
- struct capn_stream z;
- memset(&z, 0, sizeof(z));
- return init_fp(c, f, &z, packed);
-}
-
-int capn_init_mem(struct capn *c, const uint8_t *p, size_t sz, int packed) {
- struct capn_stream z;
- memset(&z, 0, sizeof(z));
- z.next_in = p;
- z.avail_in = sz;
- return init_fp(c, NULL, &z, packed);
-}
-
-static void header_calc(struct capn *c, uint32_t *headerlen, size_t *headersz)
-{
- /* segnum == 1:
- * [segnum][segsiz]
- * segnum == 2:
- * [segnum][segsiz][segsiz][zeroes]
- * segnum == 3:
- * [segnum][segsiz][segsiz][segsiz]
- * segnum == 4:
- * [segnum][segsiz][segsiz][segsiz][segsiz][zeroes]
- */
- *headerlen = ((2 + c->segnum) / 2) * 2;
- *headersz = 4 * *headerlen;
-}
-
-static int header_render(struct capn *c, struct capn_segment *seg, uint32_t *header, uint32_t headerlen, size_t *datasz)
-{
- size_t i;
-
- header[0] = capn_flip32(c->segnum - 1);
- header[headerlen-1] = 0; /* Zero out the spare position in the header sizes */
- for (i = 0; i < c->segnum; i++, seg = seg->next) {
- if (0 == seg)
- return -1;
- *datasz += seg->len;
- header[1 + i] = capn_flip32(seg->len / 8);
- }
- if (0 != seg)
- return -1;
-
- return 0;
-}
-
-static int capn_write_mem_packed(struct capn *c, uint8_t *p, size_t sz)
-{
- struct capn_segment *seg;
- struct capn_ptr root;
- uint32_t headerlen;
- size_t headersz, datasz = 0;
- uint32_t *header;
- struct capn_stream z;
- int ret;
-
- root = capn_root(c);
- header_calc(c, &headerlen, &headersz);
- header = (uint32_t*) (p + headersz + 2); /* must reserve two bytes for worst case expansion */
-
- if (sz < headersz*2 + 2) /* We must have space for temporary writing of header to deflate */
- return -1;
-
- ret = header_render(c, root.seg, header, headerlen, &datasz);
- if (ret != 0)
- return -1;
-
- memset(&z, 0, sizeof(z));
- z.next_in = (uint8_t *)header;
- z.avail_in = headersz;
- z.next_out = p;
- z.avail_out = sz;
-
- // pack the headers
- ret = capn_deflate(&z);
- if (ret != 0 || z.avail_in != 0)
- return -1;
-
- for (seg = root.seg; seg; seg = seg->next) {
- z.next_in = (uint8_t *)seg->data;
- z.avail_in = seg->len;
- ret = capn_deflate(&z);
- if (ret != 0 || z.avail_in != 0)
- return -1;
- }
-
- return sz - z.avail_out;
-}
-
-int
-capn_write_mem(struct capn *c, uint8_t *p, size_t sz, int packed)
-{
- struct capn_segment *seg;
- struct capn_ptr root;
- uint32_t headerlen;
- size_t headersz, datasz = 0;
- uint32_t *header;
- int ret;
-
- if (c->segnum == 0)
- return -1;
-
- if (packed)
- return capn_write_mem_packed(c, p, sz);
-
- root = capn_root(c);
- header_calc(c, &headerlen, &headersz);
- header = (uint32_t*) p;
-
- if (sz < headersz)
- return -1;
-
- ret = header_render(c, root.seg, header, headerlen, &datasz);
- if (ret != 0)
- return -1;
-
- if (sz < headersz + datasz)
- return -1;
-
- p += headersz;
-
- for (seg = root.seg; seg; seg = seg->next) {
- memcpy(p, seg->data, seg->len);
- p += seg->len;
- }
-
- return headersz+datasz;
-}
-
-static int _write_fd(ssize_t (*write_fd)(int fd, const void *p, size_t count), int fd, void *p, size_t count)
-{
- ssize_t ret;
- size_t sent = 0;
-
- while (sent < count) {
- ret = write_fd(fd, ((uint8_t*)p)+sent, count-sent);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- else
- return -1;
- }
- sent += ret;
- }
-
- return 0;
-}
-
-int capn_write_fd(struct capn *c, ssize_t (*write_fd)(int fd, const void *p, size_t count), int fd, int packed)
-{
- unsigned char buf[4096];
- struct capn_segment *seg;
- struct capn_ptr root;
- uint32_t headerlen;
- size_t headersz, datasz = 0;
- int ret;
- struct capn_stream z;
- unsigned char *p;
-
- if (c->segnum == 0)
- return -1;
-
- root = capn_root(c);
- header_calc(c, &headerlen, &headersz);
-
- if (sizeof(buf) < headersz)
- return -1;
-
- ret = header_render(c, root.seg, (uint32_t*)buf, headerlen, &datasz);
- if (ret != 0)
- return -1;
-
- if (packed) {
- const int headerrem = sizeof(buf) - headersz;
- const int maxpack = headersz + 2;
- if (headerrem < maxpack)
- return -1;
-
- memset(&z, 0, sizeof(z));
- z.next_in = buf;
- z.avail_in = headersz;
- z.next_out = buf + headersz;
- z.avail_out = headerrem;
- ret = capn_deflate(&z);
- if (ret != 0)
- return -1;
-
- p = buf + headersz;
- headersz = headerrem - z.avail_out;
- } else {
- p = buf;
- }
-
- ret = _write_fd(write_fd, fd, p, headersz);
- if (ret < 0)
- return -1;
-
- datasz = headersz;
- for (seg = root.seg; seg; seg = seg->next) {
- size_t bufsz;
- if (packed) {
- memset(&z, 0, sizeof(z));
- z.next_in = (uint8_t*)seg->data;
- z.avail_in = seg->len;
- z.next_out = buf;
- z.avail_out = sizeof(buf);
- ret = capn_deflate(&z);
- if (ret != 0)
- return -1;
- p = buf;
- bufsz = sizeof(buf) - z.avail_out;
- } else {
- p = (uint8_t*)seg->data;
- bufsz = seg->len;
- }
- ret = _write_fd(write_fd, fd, p, bufsz);
- if (ret < 0)
- return -1;
- datasz += bufsz;
- }
-
- return datasz;
-}
diff --git a/src/lib/capnp-c/capn-stream.cc b/src/lib/capnp-c/capn-stream.cc
deleted file mode 100644
index 135d1b2..0000000
--- a/src/lib/capnp-c/capn-stream.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-/* vim: set sw=8 ts=8 sts=8 noet: */
-/* capn-stream.c
- *
- * Copyright (C) 2013 James McKaskill
- *
- * This software may be modified and distributed under the terms
- * of the MIT license. See the LICENSE file for details.
- */
-
-#include "capnp_c.h"
-#include "capnp_priv.h"
-#include <string.h>
-
-#ifndef min
-static unsigned min(unsigned a, unsigned b) { return (a < b) ? a : b; }
-#endif
-
-int capn_deflate(struct capn_stream* s) {
- if (s->avail_in % 8) {
- return CAPN_MISALIGNED;
- }
-
- while (s->avail_in) {
- int i;
- size_t sz;
- uint8_t hdr = 0;
- uint8_t *p;
-
- if (!s->avail_out)
- return CAPN_NEED_MORE;
-
- if (s->raw > 0) {
- sz = min(s->raw, min(s->avail_in, s->avail_out));
- memcpy(s->next_out, s->next_in, sz);
- s->next_out += sz;
- s->next_in += sz;
- s->avail_out -= sz;
- s->avail_in -= sz;
- s->raw -= sz;
- continue;
- }
-
- if (s->avail_in < 8)
- return CAPN_NEED_MORE;
-
- sz = 0;
- for (i = 0; i < 8; i++) {
- if (s->next_in[i]) {
- sz ++;
- hdr |= 1 << i;
- }
- }
-
- switch (sz) {
- case 0:
- if (s->avail_out < 2)
- return CAPN_NEED_MORE;
-
- s->next_out[0] = 0;
- for (sz = 1; sz < min(s->avail_in/8, 256); sz++) {
- if (((uint64_t*) s->next_in)[sz] != 0) {
- break;
- }
- }
-
- s->next_out[1] = (uint8_t) (sz-1);
- s->next_in += sz*8;
- s->avail_in -= sz*8;
- s->next_out += 2;
- s->avail_out -= 2;
- continue;
-
- case 8:
- if (s->avail_out < 10)
- return CAPN_NEED_MORE;
-
- s->next_out[0] = 0xFF;
- memcpy(s->next_out+1, s->next_in, 8);
- s->next_in += 8;
- s->avail_in -= 8;
-
- s->raw = min(s->avail_in, 256*8);
- if ((p = (uint8_t*) memchr(s->next_in, 0, s->raw)) != NULL) {
- s->raw = (p - s->next_in) & ~7;
- }
-
- s->next_out[9] = (uint8_t) (s->raw/8);
- s->next_out += 10;
- s->avail_out -= 10;
- continue;
-
- default:
- if (s->avail_out < 1U + sz)
- return CAPN_NEED_MORE;
-
- *(s->next_out++) = hdr;
- for (i = 0; i < 8; i++) {
- if (s->next_in[i]) {
- *(s->next_out++) = s->next_in[i];
- }
- }
- s->avail_out -= sz + 1;
- s->next_in += 8;
- s->avail_in -= 8;
- continue;
- }
- }
-
- return 0;
-}
-
-int capn_inflate(struct capn_stream* s) {
- while (s->avail_out) {
- int i;
- size_t sz;
- uint8_t hdr;
- uint8_t *wr;
-
- if (s->avail_buf && s->avail_out >= s->avail_buf) {
- memcpy(s->next_out, s->inflate_buf, s->avail_buf);
- s->next_out += s->avail_buf;
- s->avail_out -= s->avail_buf;
- s->avail_buf = 0;
- if (!s->avail_out)
- return 0;
- }
- if (s->avail_buf && s->avail_out < s->avail_buf) {
- memcpy(s->next_out, s->inflate_buf, s->avail_out);
- memmove(s->inflate_buf, s->inflate_buf + s->avail_out,
- s->avail_buf - s->avail_out);
- s->avail_buf -= s->avail_out;
- s->avail_out = 0;
- return 0;
- }
-
- if (s->zeros > 0) {
- sz = min(s->avail_out, s->zeros);
- memset(s->next_out, 0, sz);
- s->next_out += sz;
- s->avail_out -= sz;
- s->zeros -= sz;
- continue;
- }
-
- if (s->raw > 0) {
- if (s->avail_in == 0)
- return CAPN_NEED_MORE;
-
- sz = min(min(s->avail_out, s->raw), s->avail_in);
- memcpy(s->next_out, s->next_in, sz);
- s->next_in += sz;
- s->next_out += sz;
- s->avail_in -= sz;
- s->avail_out -= sz;
- s->raw -= sz;
- continue;
- }
-
- if (s->avail_in == 0)
- return 0;
- else if (s->avail_in < 2)
- return CAPN_NEED_MORE;
-
- switch (s->next_in[0]) {
- case 0xFF:
- /* 0xFF is followed by 8 bytes raw, followed by
- * a byte with length in words to read raw */
- if (s->avail_in < 10)
- return CAPN_NEED_MORE;
-
- memcpy(s->inflate_buf, s->next_in+1, 8);
- s->avail_buf = 8;
-
- s->raw = s->next_in[9] * 8;
- s->next_in += 10;
- s->avail_in -= 10;
- continue;
-
- case 0x00:
- /* 0x00 is followed by a single byte indicating
- * the count of consecutive zero value words
- * minus 1 */
- s->zeros = (s->next_in[1] + 1) * 8;
- s->next_in += 2;
- s->avail_in -= 2;
- continue;
-
- default:
- hdr = s->next_in[0];
- sz = 0;
- for (i = 0; i < 8; i++) {
- if (hdr & (1 << i))
- sz++;
- }
- if (s->avail_in < 1U + sz)
- return CAPN_NEED_MORE;
-
- s->next_in += 1;
-
- wr = s->inflate_buf;
- for (i = 0; i < 8; i++) {
- if (hdr & (1 << i)) {
- *wr++ = *s->next_in++;
- } else {
- *wr++ = 0;
- }
- }
-
- s->avail_buf = 8;
- s->avail_in -= 1 + sz;
- continue;
- }
- }
-
- return 0;
-}
-
diff --git a/src/lib/capnp-c/capn.cc b/src/lib/capnp-c/capn.cc
deleted file mode 100644
index bbd7be3..0000000
--- a/src/lib/capnp-c/capn.cc
+++ /dev/null
@@ -1,1117 +0,0 @@
-/* vim: set sw=8 ts=8 sts=8 noet: */
-/* capn.c
- *
- * Copyright (C) 2013 James McKaskill
- *
- * This software may be modified and distributed under the terms
- * of the MIT license. See the LICENSE file for details.
- */
-
-#ifdef __GNUC__
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-
-#include "capnp_c.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef _MSC_VER
-#ifndef MULTIPASS_ARCH_arduino_nano
-#include <sys/param.h>
-#endif
-#endif
-
-#define STRUCT_PTR 0
-#define LIST_PTR 1
-#define FAR_PTR 2
-#define DOUBLE_PTR 6
-
-#define VOID_LIST 0
-#define BIT_1_LIST 1
-#define BYTE_1_LIST 2
-#define BYTE_2_LIST 3
-#define BYTE_4_LIST 4
-#define BYTE_8_LIST 5
-#define PTR_LIST 6
-#define COMPOSITE_LIST 7
-
-#define U64(val) ((uint64_t) (val))
-#define I64(val) ((int64_t) (val))
-#define U32(val) ((uint32_t) (val))
-#define I32(val) ((int32_t) (val))
-#define U16(val) ((uint16_t) (val))
-#define I16(val) ((int16_t) (val))
-
-#ifndef min
-static int min(int a, int b) { return (a < b) ? a : b; }
-#endif
-
-#ifdef BYTE_ORDER
-#define CAPN_LITTLE (BYTE_ORDER == LITTLE_ENDIAN)
-#elif defined(__BYTE_ORDER)
-#define CAPN_LITTLE (__BYTE_ORDER == __LITTLE_ENDIAN)
-#else
-#define CAPN_LITTLE 0
-#endif
-
-struct capn_tree *capn_tree_insert(struct capn_tree *root, struct capn_tree *n) {
- n->red = 1;
- n->link[0] = n->link[1] = NULL;
-
- for (;;) {
- /* parent, uncle, grandparent, great grandparent link */
- struct capn_tree *p, *u, *g, **gglink;
- int dir;
-
- /* Case 1: N is root */
- p = n->parent;
- if (!p) {
- n->red = 0;
- root = n;
- break;
- }
-
- /* Case 2: p is black */
- if (!p->red) {
- break;
- }
-
- g = p->parent;
- dir = (p == g->link[1]);
-
- /* Case 3: P and U are red, switch g to red, but must
- * loop as G could be root or have a red parent
- * g to G
- * / \ / \
- * P U p u
- * / /
- * N N
- */
- u = g->link[!dir];
- if (u != NULL && u->red) {
- p->red = 0;
- u->red = 0;
- g->red = 1;
- n = g;
- continue;
- }
-
- if (!g->parent) {
- gglink = &root;
- } else if (g->parent->link[1] == g) {
- gglink = &g->parent->link[1];
- } else {
- gglink = &g->parent->link[0];
- }
-
- if (dir != (n == p->link[1])) {
- /* Case 4: rotate on P, then on g
- * here dir is /
- * g to g to n
- * / \ / \ / \
- * P u N u P G
- * / \ / \ /| / \
- * 1 N P 3 1 2 3 u
- * / \ / \
- * 2 3 1 2
- */
- struct capn_tree *two = n->link[dir];
- struct capn_tree *three = n->link[!dir];
- p->link[!dir] = two;
- g->link[dir] = three;
- n->link[dir] = p;
- n->link[!dir] = g;
- *gglink = n;
- n->parent = g->parent;
- p->parent = n;
- g->parent = n;
- if (two)
- two->parent = p;
- if (three)
- three->parent = g;
- n->red = 0;
- g->red = 1;
- } else {
- /* Case 5: rotate on g
- * here dir is /
- * g to p
- * / \ / \
- * P u N G
- * / \ /| / \
- * N 3 1 2 3 u
- * / \
- * 1 2
- */
- struct capn_tree *three = p->link[!dir];
- g->link[dir] = three;
- p->link[!dir] = g;
- *gglink = p;
- p->parent = g->parent;
- g->parent = p;
- if (three)
- three->parent = g;
- g->red = 1;
- p->red = 0;
- }
-
- break;
- }
-
- return root;
-}
-
-void capn_append_segment(struct capn *c, struct capn_segment *s) {
- s->id = c->segnum++;
- s->capn = c;
- s->next = NULL;
-
- if (c->lastseg) {
- c->lastseg->next = s;
- c->lastseg->hdr.link[1] = &s->hdr;
- s->hdr.parent = &c->lastseg->hdr;
- } else {
- c->seglist = s;
- s->hdr.parent = NULL;
- }
-
- c->lastseg = s;
- c->segtree = capn_tree_insert(c->segtree, &s->hdr);
-}
-
-static char *new_data(struct capn *c, int sz, struct capn_segment **ps) {
- struct capn_segment *s;
-
- /* find a segment with sufficient data */
- for (s = c->seglist; s != NULL; s = s->next) {
- if (s->len + sz <= s->cap) {
- goto end;
- }
- }
-
- s = c->create ? c->create(c->user, c->segnum, sz) : NULL;
- if (!s) {
- *ps = NULL;
- return NULL;
- }
-
- capn_append_segment(c, s);
-end:
- *ps = s;
- s->len += sz;
- return s->data + s->len - sz;
-}
-
-static struct capn_segment *lookup_segment(struct capn* c, struct capn_segment *s, uint32_t id) {
- struct capn_tree **x;
- struct capn_segment *y = NULL;
-
- if (s && s->id == id)
- return s;
- if (!c)
- return NULL;
-
- if (id < c->segnum) {
- x = &c->segtree;
- while (*x) {
- y = (struct capn_segment*) *x;
- if (id == y->id) {
- return y;
- } else if (id < y->id) {
- x = &y->hdr.link[0];
- } else {
- x = &y->hdr.link[1];
- }
- }
- } else {
- /* Otherwise `x` may be uninitialized */
- return NULL;
- }
-
- s = c->lookup ? c->lookup(c->user, id) : NULL;
- if (!s)
- return NULL;
-
- if (id < c->segnum) {
- s->id = id;
- s->capn = c;
- s->next = c->seglist;
- c->seglist = s;
- s->hdr.parent = &y->hdr;
- *x = &s->hdr;
- c->segtree = capn_tree_insert(c->segtree, &s->hdr);
- } else {
- c->segnum = id;
- capn_append_segment(c, s);
- }
-
- return s;
-}
-
-static uint64_t lookup_double(struct capn_segment **s, char **d, uint64_t val) {
- uint64_t far, tag;
- size_t off = (U32(val) >> 3) * 8;
- char *p;
-
- if ((*s = lookup_segment((*s)->capn, *s, U32(val >> 32))) == NULL) {
- return 0;
- }
-
- p = (*s)->data + off;
- if (off + 16 > (*s)->len) {
- return 0;
- }
-
- far = capn_flip64(*(uint64_t*) p);
- tag = capn_flip64(*(uint64_t*) (p+8));
-
- /* the far tag should not be another double, and the tag
- * should be struct/list and have no offset */
- if ((far&7) != FAR_PTR || U32(tag) > LIST_PTR) {
- return 0;
- }
-
- if ((*s = lookup_segment((*s)->capn, *s, U32(far >> 32))) == NULL) {
- return 0;
- }
-
- /* -8 because far pointers reference from the start of
- * the segment, but offsets reference the end of the
- * pointer data. Here *d points to where an equivalent
- * ptr would be.
- */
- *d = (*s)->data - 8;
- return U64(U32(far) >> 3 << 2) | tag;
-}
-
-static uint64_t lookup_far(struct capn_segment **s, char **d, uint64_t val) {
- size_t off = (U32(val) >> 3) * 8;
-
- if ((*s = lookup_segment((*s)->capn, *s, U32(val >> 32))) == NULL) {
- return 0;
- }
-
- if (off + 8 > (*s)->len) {
- return 0;
- }
-
- *d = (*s)->data + off;
- return capn_flip64(*(uint64_t*)*d);
-}
-
-static char *struct_ptr(struct capn_segment *s, char *d, int minsz) {
- uint64_t val = capn_flip64(*(uint64_t*)d);
- uint16_t datasz;
-
- switch (val&7) {
- case FAR_PTR:
- val = lookup_far(&s, &d, val);
- break;
- case DOUBLE_PTR:
- val = lookup_double(&s, &d, val);
- break;
- }
-
- datasz = U16(val >> 32);
- d += (I32(U32(val)) << 1) + 8;
-
- if (val != 0 && (val&3) != STRUCT_PTR && datasz >= minsz && s->data <= d && d < s->data + s->len) {
- return d;
- }
-
- return NULL;
-}
-
-static capn_ptr read_ptr(struct capn_segment *s, char *d) {
- capn_ptr ret = {CAPN_NULL};
- uint64_t val;
- char *e = 0;
-
- val = capn_flip64(*(uint64_t*) d);
-
- switch (val&7) {
- case FAR_PTR:
- val = lookup_far(&s, &d, val);
- ret.has_ptr_tag = (U32(val) >> 2) == 0;
- break;
- case DOUBLE_PTR:
- val = lookup_double(&s, &d, val);
- break;
- }
-
- d += (I32(U32(val)) >> 2) * 8 + 8;
-
- if (d < s->data) {
- goto err;
- }
-
- switch (val & 3) {
- case STRUCT_PTR:
- ret.type = val ? CAPN_STRUCT : CAPN_NULL;
- goto struct_common;
-
- struct_common:
- ret.datasz = U32(U16(val >> 32)) * 8;
- ret.ptrs = U32(U16(val >> 48));
- e = d + ret.datasz + 8 * ret.ptrs;
- break;
-
- case LIST_PTR:
- ret.type = CAPN_LIST;
- ret.len = val >> 35;
-
- switch ((val >> 32) & 7) {
- case VOID_LIST:
- e = d;
- break;
- case BIT_1_LIST:
- ret.type = CAPN_BIT_LIST;
- ret.datasz = (ret.len+7)/8;
- e = d + ret.datasz;
- break;
- case BYTE_1_LIST:
- ret.datasz = 1;
- e = d + ret.len;
- break;
- case BYTE_2_LIST:
- ret.datasz = 2;
- e = d + ret.len * 2;
- break;
- case BYTE_4_LIST:
- ret.datasz = 4;
- e = d + ret.len * 4;
- break;
- case BYTE_8_LIST:
- ret.datasz = 8;
- e = d + ret.len * 8;
- break;
- case PTR_LIST:
- ret.type = CAPN_PTR_LIST;
- e = d + ret.len * 8;
- break;
- case COMPOSITE_LIST:
- if ((size_t)((d+8) - s->data) > s->len) {
- goto err;
- }
-
- val = capn_flip64(*(uint64_t*) d);
-
- d += 8;
- e = d + ret.len * 8;
-
- ret.datasz = U32(U16(val >> 32)) * 8;
- ret.ptrs = U32(U16(val >> 48));
- ret.len = U32(val) >> 2;
- ret.is_composite_list = 1;
-
- if ((ret.datasz + 8*ret.ptrs) * ret.len != e - d) {
- goto err;
- }
- break;
- }
- break;
-
- default:
- goto err;
- }
-
- if ((size_t)(e - s->data) > s->len)
- goto err;
-
- ret.data = d;
- ret.seg = s;
- return ret;
-err:
- memset(&ret, 0, sizeof(ret));
- return ret;
-}
-
-void capn_resolve(capn_ptr *p) {
- if (p->type == CAPN_FAR_POINTER) {
- *p = read_ptr(p->seg, p->data);
- }
-}
-
-/* TODO: should this handle CAPN_BIT_LIST? */
-capn_ptr capn_getp(capn_ptr p, int off, int resolve) {
- capn_ptr ret = {CAPN_FAR_POINTER};
- ret.seg = p.seg;
-
- capn_resolve(&p);
-
- switch (p.type) {
- case CAPN_LIST:
- /* Return an inner pointer */
- if (off < p.len) {
- capn_ptr ret = {CAPN_STRUCT};
- ret.is_list_member = 1;
- ret.data = p.data + off * (p.datasz + 8*p.ptrs);
- ret.seg = p.seg;
- ret.datasz = p.datasz;
- ret.ptrs = p.ptrs;
- return ret;
- } else {
- goto err;
- }
-
- case CAPN_STRUCT:
- if (off >= p.ptrs) {
- goto err;
- }
- ret.data = p.data + p.datasz + 8*off;
- break;
-
- case CAPN_PTR_LIST:
- if (off >= p.len) {
- goto err;
- }
- ret.data = p.data + 8*off;
- break;
-
- default:
- goto err;
- }
-
- if (resolve) {
- ret = read_ptr(ret.seg, ret.data);
- }
-
- return ret;
-
-err:
- memset(&p, 0, sizeof(p));
- return p;
-}
-
-static void write_ptr_tag(char *d, capn_ptr p, int off) {
- uint64_t val = U64(U32(I32(off/8) << 2));
-
- switch (p.type) {
- case CAPN_STRUCT:
- val |= STRUCT_PTR | (U64(p.datasz/8) << 32) | (U64(p.ptrs) << 48);
- break;
-
- case CAPN_LIST:
- if (p.is_composite_list) {
- val |= LIST_PTR | (U64(COMPOSITE_LIST) << 32) | (U64(p.len * (p.datasz/8 + p.ptrs)) << 35);
- } else {
- val |= LIST_PTR | (U64(p.len) << 35);
-
- switch (p.datasz) {
- case 8:
- val |= (U64(BYTE_8_LIST) << 32);
- break;
- case 4:
- val |= (U64(BYTE_4_LIST) << 32);
- break;
- case 2:
- val |= (U64(BYTE_2_LIST) << 32);
- break;
- case 1:
- val |= (U64(BYTE_1_LIST) << 32);
- break;
- case 0:
- val |= (U64(VOID_LIST) << 32);
- break;
- }
- }
- break;
-
- case CAPN_BIT_LIST:
- val |= LIST_PTR | (U64(BIT_1_LIST) << 32) | (U64(p.len) << 35);
- break;
-
- case CAPN_PTR_LIST:
- val |= LIST_PTR | (U64(PTR_LIST) << 32) | (U64(p.len) << 35);
- break;
-
- default:
- val = 0;
- break;
- }
-
- *(uint64_t*) d = capn_flip64(val);
-}
-
-static void write_far_ptr(char *d, struct capn_segment *s, char *tgt) {
- *(uint64_t*) d = capn_flip64(FAR_PTR | U64(tgt - s->data) | (U64(s->id) << 32));
-}
-
-static void write_double_far(char *d, struct capn_segment *s, char *tgt) {
- *(uint64_t*) d = capn_flip64(DOUBLE_PTR | U64(tgt - s->data) | (U64(s->id) << 32));
-}
-
-#define NEED_TO_COPY 1
-
-static int write_ptr(struct capn_segment *s, char *d, capn_ptr p) {
- /* note p.seg can be NULL if its a ptr to static data */
- char *pdata = p.data - 8*p.is_composite_list;
-
- if (p.type == CAPN_NULL || (p.type == CAPN_STRUCT && p.datasz == 0 && p.ptrs == 0)) {
- write_ptr_tag(d, p, 0);
- return 0;
-
- } else if (!p.seg || p.seg->capn != s->capn || p.is_list_member) {
- return NEED_TO_COPY;
-
- } else if (p.seg == s) {
- write_ptr_tag(d, p, pdata - d - 8);
- return 0;
-
- } else if (p.has_ptr_tag) {
- /* By lucky chance, the data has a tag in front
- * of it. This happens when new_object had to move
- * the data to a new segment. */
- write_far_ptr(d, p.seg, pdata-8);
- return 0;
-
- } else if (p.seg->len + 8 <= p.seg->cap) {
- /* The target segment has enough room for tag */
- char *t = p.seg->data + p.seg->len;
- write_ptr_tag(t, p, pdata - t - 8);
- write_far_ptr(d, p.seg, t);
- p.seg->len += 8;
- return 0;
-
- } else {
- /* have to allocate room for a double far
- * pointer */
- char *t;
-
- if (s->len + 16 <= s->cap) {
- /* Try and allocate in the src segment
- * first. This should improve lookup on
- * read. */
- t = s->data + s->len;
- s->len += 16;
- } else {
- t = new_data(s->capn, 16, &s);
- if (!t) return -1;
- }
-
- write_far_ptr(t, p.seg, pdata);
- write_ptr_tag(t+8, p, 0);
- write_double_far(d, s, t);
- return 0;
- }
-}
-
-struct copy {
- struct capn_tree hdr;
- struct capn_ptr to, from;
- char *fbegin, *fend;
-};
-
-static capn_ptr new_clone(struct capn_segment *s, capn_ptr p) {
- switch (p.type) {
- case CAPN_STRUCT:
- return capn_new_struct(s, p.datasz, p.ptrs);
- case CAPN_PTR_LIST:
- return capn_new_ptr_list(s, p.len);
- case CAPN_BIT_LIST:
- return capn_new_list1(s, p.len).p;
- case CAPN_LIST:
- return capn_new_list(s, p.len, p.datasz, p.ptrs);
- default:
- return p;
- }
-}
-
-static int is_ptr_equal(const struct capn_ptr *a, const struct capn_ptr *b) {
- return a->data == b->data
- && a->type == b->type
- && a->len == b->len
- && a->datasz == b->datasz
- && a->ptrs == b->ptrs;
-}
-
-static int data_size(struct capn_ptr p) {
- switch (p.type) {
- case CAPN_BIT_LIST:
- return p.datasz;
- case CAPN_PTR_LIST:
- return p.len*8;
- case CAPN_STRUCT:
- return p.datasz + 8*p.ptrs;
- case CAPN_LIST:
- return p.len * (p.datasz + 8*p.ptrs) + 8*p.is_composite_list;
- default:
- return 0;
- }
-}
-
-static int copy_ptr(struct capn_segment *seg, char *data, struct capn_ptr *t, struct capn_ptr *f, int *dep) {
- struct capn *c = seg->capn;
- struct copy *cp = NULL;
- struct capn_tree **xcp;
- char *fbegin = f->data - 8*f->is_composite_list;
- char *fend = fbegin + data_size(*f);
- int zero_sized = (fend == fbegin);
-
- /* We always copy list members as it would otherwise be an
- * overlapped pointer (the data is owned by the enclosing list).
- * We do not bother with the overlapped lookup for zero sized
- * structures/lists as they never overlap. Nor do we add them to
- * the copy list as there is no data to be shared by multiple
- * pointers.
- */
-
- xcp = &c->copy;
- while (*xcp && !zero_sized) {
- cp = (struct copy*) *xcp;
- if (fend <= cp->fbegin) {
- xcp = &cp->hdr.link[0];
- } else if (cp->fend <= fbegin) {
- xcp = &cp->hdr.link[1];
- } else if (is_ptr_equal(f, &cp->from)) {
- /* we already have a copy so just point to that */
- return write_ptr(seg, data, cp->to);
- } else {
- /* pointer to overlapped data */
- return -1;
- }
- }
-
- /* no copy found - have to create a new copy */
- *t = new_clone(seg, *f);
-
- if (write_ptr(seg, data, *t))
- return -1;
-
- /* add the copy to the copy tree so we can look for overlapping
- * source pointers and handle recursive structures */
- if (!zero_sized) {
- struct copy *n;
- struct capn_segment *cs = c->copylist;
-
- /* need to allocate a struct copy */
- if (!cs || cs->len + (int)sizeof(*n) > cs->cap) {
- cs = c->create_local ? c->create_local(c->user, sizeof(*n)) : NULL;
- if (!cs) {
- /* can't allocate a copy structure */
- return -1;
- }
- cs->next = c->copylist;
- c->copylist = cs;
- }
-
- n = (struct copy*) (cs->data + cs->len);
- cs->len += sizeof(*n);
-
- n->from = *f;
- n->to = *t;
- n->fbegin = fbegin;
- n->fend = fend;
-
- *xcp = &n->hdr;
- n->hdr.parent = &cp->hdr;
-
- c->copy = capn_tree_insert(c->copy, &n->hdr);
- }
-
- /* minimize the number of types the main copy routine has to
- * deal with to just CAPN_LIST and CAPN_PTR_LIST. ptr list only
- * needs t->type, t->len, t->data, t->seg, f->data, f->seg to
- * be valid */
- switch (t->type) {
- case CAPN_STRUCT:
- if (t->datasz) {
- memcpy(t->data, f->data, t->datasz);
- t->data += t->datasz;
- f->data += t->datasz;
- }
- if (t->ptrs) {
- t->type = CAPN_PTR_LIST;
- t->len = t->ptrs;
- (*dep)++;
- }
- return 0;
-
- case CAPN_BIT_LIST:
- memcpy(t->data, f->data, t->datasz);
- return 0;
-
- case CAPN_LIST:
- if (!t->len) {
- /* empty list - nothing to copy */
- } else if (t->ptrs && t->datasz) {
- (*dep)++;
- } else if (t->datasz) {
- memcpy(t->data, f->data, t->len * t->datasz);
- } else if (t->ptrs) {
- t->type = CAPN_PTR_LIST;
- t->len *= t->ptrs;
- (*dep)++;
- }
- return 0;
-
- case CAPN_PTR_LIST:
- if (t->len) {
- (*dep)++;
- }
- return 0;
-
- default:
- return -1;
- }
-}
-
-static void copy_list_member(capn_ptr* t, capn_ptr *f, int *dep) {
- /* copy struct data */
- int sz = min(t->datasz, f->datasz);
- memcpy(t->data, f->data, sz);
- memset(t->data + sz, 0, t->datasz - sz);
- t->data += t->datasz;
- f->data += f->datasz;
-
- /* reset excess pointers */
- sz = min(t->ptrs, f->ptrs);
- memset(t->data + sz, 0, 8*(t->ptrs - sz));
-
- /* create a pointer list for the main loop to copy */
- if (t->ptrs) {
- t->type = CAPN_PTR_LIST;
- t->len = t->ptrs;
- (*dep)++;
- }
-}
-
-#define MAX_COPY_DEPTH 32
-
-/* TODO: handle CAPN_BIT_LIST and setting from an inner bit list member */
-int capn_setp(capn_ptr p, int off, capn_ptr tgt) {
- struct capn_ptr to[MAX_COPY_DEPTH], from[MAX_COPY_DEPTH];
- char *data;
- int err, dep = 0;
-
- capn_resolve(&p);
-
- if (tgt.type == CAPN_FAR_POINTER && tgt.seg->capn == p.seg->capn) {
- uint64_t val = capn_flip64(*(uint64_t*) tgt.data);
- if ((val & 3) == FAR_PTR) {
- *(uint64_t*) p.data = *(uint64_t*) tgt.data;
- return 0;
- }
- }
-
- capn_resolve(&tgt);
-
- switch (p.type) {
- case CAPN_LIST:
- if (off >= p.len || tgt.type != CAPN_STRUCT)
- return -1;
-
- to[0] = p;
- to[0].data += off * (p.datasz + 8*p.ptrs);
- from[0] = tgt;
- copy_list_member(to, from, &dep);
- break;
-
- case CAPN_PTR_LIST:
- if (off >= p.len)
- return -1;
- data = p.data + 8*off;
- goto copy_ptr;
-
- case CAPN_STRUCT:
- if (off >= p.ptrs)
- return -1;
- data = p.data + p.datasz + 8*off;
- goto copy_ptr;
-
- copy_ptr:
- err = write_ptr(p.seg, data, tgt);
- if (err != NEED_TO_COPY)
- return err;
-
- /* Depth first copy the source whilst using a pointer stack to
- * maintain the ptr to set and size left to copy at each level.
- * We also maintain a rbtree (capn->copy) of the copies indexed
- * by the source data. This way we can detect overlapped
- * pointers in the source (and bail) and recursive structures
- * (and point to the previous copy).
- */
-
- from[0] = tgt;
- if (copy_ptr(p.seg, data, to, from, &dep))
- return -1;
- break;
-
- default:
- return -1;
- }
-
- while (dep) {
- struct capn_ptr *tc = &to[dep-1], *tn = &to[dep];
- struct capn_ptr *fc = &from[dep-1], *fn = &from[dep];
-
- if (dep+1 == MAX_COPY_DEPTH) {
- return -1;
- }
-
- if (!tc->len) {
- dep--;
- continue;
- }
-
- if (tc->type == CAPN_LIST) {
- *fn = capn_getp(*fc, 0, 1);
- *tn = capn_getp(*tc, 0, 1);
-
- copy_list_member(tn, fn, &dep);
-
- fc->data += fc->datasz + 8*fc->ptrs;
- tc->data += tc->datasz + 8*tc->ptrs;
- tc->len--;
-
- } else { /* CAPN_PTR_LIST */
- *fn = read_ptr(fc->seg, fc->data);
-
- if (fn->type && copy_ptr(tc->seg, tc->data, tn, fn, &dep))
- return -1;
-
- fc->data += 8;
- tc->data += 8;
- tc->len--;
- }
- }
-
- return 0;
-}
-
-/* TODO: handle CAPN_LIST, CAPN_PTR_LIST for bit lists */
-
-int capn_get1(capn_list1 l, int off) {
- return l.p.type == CAPN_BIT_LIST
- && off < l.p.len
- && (l.p.data[off/8] & (1 << (off%8))) != 0;
-}
-
-int capn_set1(capn_list1 l, int off, int val) {
- if (l.p.type != CAPN_BIT_LIST || off >= l.p.len)
- return -1;
- if (val) {
- l.p.data[off/8] |= 1 << (off%8);
- } else {
- l.p.data[off/8] &= ~(1 << (off%8));
- }
- return 0;
-}
-
-int capn_getv1(capn_list1 l, int off, uint8_t *data, int sz) {
- /* Note we only support aligned reads */
- int bsz;
- capn_ptr p;
- capn_resolve(&l.p);
- p = l.p;
- if (p.type != CAPN_BIT_LIST || (off & 7) != 0)
- return -1;
-
- bsz = (sz + 7) / 8;
- off /= 8;
-
- if (off + sz > p.datasz) {
- memcpy(data, p.data + off, p.datasz - off);
- return p.len - off*8;
- } else {
- memcpy(data, p.data + off, bsz);
- return sz;
- }
-}
-
-int capn_setv1(capn_list1 l, int off, const uint8_t *data, int sz) {
- /* Note we only support aligned writes */
- int bsz;
- capn_ptr p = l.p;
- if (p.type != CAPN_BIT_LIST || (off & 7) != 0)
- return -1;
-
- bsz = (sz + 7) / 8;
- off /= 8;
-
- if (off + sz > p.datasz) {
- memcpy(p.data + off, data, p.datasz - off);
- return p.len - off*8;
- } else {
- memcpy(p.data + off, data, bsz);
- return sz;
- }
-}
-
-/* pull out whether we add a tag or not as a define so the unit test can
- * test double far pointers by not creating tags */
-#ifndef ADD_TAG
-#define ADD_TAG 1
-#endif
-
-static void new_object(capn_ptr *p, int bytes) {
- struct capn_segment *s = p->seg;
-
- if (!s) {
- memset(p, 0, sizeof(*p));
- return;
- }
-
- /* pointer needs to be initialised to get a valid offset on write */
- if (!bytes) {
- p->data = s->data + s->len;
- return;
- }
-
- /* all allocations are 8 byte aligned */
- bytes = (bytes + 7) & ~7;
-
- if (s->len + bytes <= s->cap) {
- p->data = s->data + s->len;
- s->len += bytes;
- return;
- }
-
- /* add a tag whenever we switch segments so that write_ptr can
- * use it */
- p->data = new_data(s->capn, bytes + ADD_TAG*8, &p->seg);
- if (!p->data) {
- memset(p, 0, sizeof(*p));
- return;
- }
-
- if (ADD_TAG) {
- write_ptr_tag(p->data, *p, 0);
- p->data += 8;
- p->has_ptr_tag = 1;
- }
-}
-
-capn_ptr capn_root(struct capn *c) {
- capn_ptr r = {CAPN_PTR_LIST};
- r.seg = lookup_segment(c, NULL, 0);
- r.data = r.seg ? r.seg->data : new_data(c, 8, &r.seg);
- r.len = 1;
-
- if (!r.seg || r.seg->cap < 8) {
- memset(&r, 0, sizeof(r));
- } else if (r.seg->len < 8) {
- r.seg->len = 8;
- }
-
- return r;
-}
-
-capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) {
- capn_ptr p = {CAPN_STRUCT};
- p.seg = seg;
- p.datasz = (datasz + 7) & ~7;
- p.ptrs = ptrs;
- new_object(&p, p.datasz + 8*p.ptrs);
- return p;
-}
-
-capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) {
- capn_ptr p = {CAPN_LIST};
- p.seg = seg;
- p.len = sz;
-
- if (ptrs || datasz > 8) {
- p.is_composite_list = 1;
- p.datasz = (datasz + 7) & ~7;
- p.ptrs = ptrs;
- new_object(&p, p.len * (p.datasz + 8*p.ptrs) + 8);
- if (p.data) {
- uint64_t hdr = STRUCT_PTR | (U64(p.len) << 2) | (U64(p.datasz/8) << 32) | (U64(ptrs) << 48);
- *(uint64_t*) p.data = capn_flip64(hdr);
- p.data += 8;
- }
- } else if (datasz > 4) {
- p.datasz = 8;
- new_object(&p, p.len * 8);
- } else if (datasz > 2) {
- p.datasz = 4;
- new_object(&p, p.len * 4);
- } else {
- p.datasz = datasz;
- new_object(&p, p.len * datasz);
- }
-
- return p;
-}
-
-capn_list1 capn_new_list1(struct capn_segment *seg, int sz) {
- capn_list1 l = {{CAPN_BIT_LIST}};
- l.p.seg = seg;
- l.p.datasz = (sz+7)/8;
- l.p.len = sz;
- new_object(&l.p, l.p.datasz);
- return l;
-}
-
-capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) {
- capn_ptr p = {CAPN_PTR_LIST};
- p.seg = seg;
- p.len = sz;
- p.ptrs = 0;
- p.datasz = 0;
- new_object(&p, sz*8);
- return p;
-}
-
-capn_ptr capn_new_string(struct capn_segment *seg, const char *str, ssize_t sz) {
- capn_ptr p = {CAPN_LIST};
- p.seg = seg;
- p.len = ((sz >= 0) ? (size_t)sz : strlen(str)) + 1;
- p.datasz = 1;
- new_object(&p, p.len);
- if (p.data) {
- memcpy(p.data, str, p.len - 1);
- p.data[p.len - 1] = '\0';
- }
- return p;
-}
-
-capn_text capn_get_text(capn_ptr p, int off, capn_text def) {
- capn_ptr m = capn_getp(p, off, 1);
- capn_text ret = def;
- if (m.type == CAPN_LIST && m.datasz == 1 && m.len && m.data[m.len - 1] == 0) {
- ret.seg = m.seg;
- ret.str = m.data;
- ret.len = m.len - 1;
- }
- return ret;
-}
-
-int capn_set_text(capn_ptr p, int off, capn_text tgt) {
- capn_ptr m = {CAPN_NULL};
- if (tgt.seg) {
- m.type = CAPN_LIST;
- m.seg = tgt.seg;
- m.data = (char*)tgt.str;
- m.len = tgt.len + 1;
- m.datasz = 1;
- } else if (tgt.str) {
- m = capn_new_string(p.seg, tgt.str, tgt.len);
- }
- return capn_setp(p, off, m);
-}
-
-capn_data capn_get_data(capn_ptr p, int off) {
- capn_data ret;
- ret.p = capn_getp(p, off, 1);
- if (ret.p.type != CAPN_LIST || ret.p.datasz != 1) {
- memset(&ret, 0, sizeof(ret));
- }
- return ret;
-}
-
-#define SZ 8
-#include "capn-list.inc"
-#undef SZ
-
-#define SZ 16
-#include "capn-list.inc"
-#undef SZ
-
-#define SZ 32
-#include "capn-list.inc"
-#undef SZ
-
-#define SZ 64
-#include "capn-list.inc"
-#undef SZ
diff --git a/src/lib/mpack/mpack.cc b/src/lib/mpack/mpack.cc
deleted file mode 100644
index 67e54e8..0000000
--- a/src/lib/mpack/mpack.cc
+++ /dev/null
@@ -1,6440 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2018 Nicholas Fraser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-/*
- * This is the MPack 1.0 amalgamation package.
- *
- * http://github.com/ludocode/mpack
- */
-
-#define MPACK_INTERNAL 1
-#define MPACK_EMIT_INLINE_DEFS 1
-
-#include "mpack.h"
-
-
-/* mpack/mpack-platform.c.c */
-
-
-// We define MPACK_EMIT_INLINE_DEFS and include mpack.h to emit
-// standalone definitions of all (non-static) inline functions in MPack.
-
-#define MPACK_INTERNAL 1
-#define MPACK_EMIT_INLINE_DEFS 1
-
-/* #include "mpack-platform.h" */
-/* #include "mpack.h" */
-
-
-#if MPACK_DEBUG && MPACK_STDIO
-#include <stdarg.h>
-#endif
-
-
-
-#if MPACK_DEBUG
-
-#if MPACK_STDIO
-void mpack_assert_fail_format(const char* format, ...) {
- char buffer[512];
- va_list args;
- va_start(args, format);
- vsnprintf(buffer, sizeof(buffer), format, args);
- va_end(args);
- buffer[sizeof(buffer) - 1] = 0;
- mpack_assert_fail_wrapper(buffer);
-}
-
-void mpack_break_hit_format(const char* format, ...) {
- char buffer[512];
- va_list args;
- va_start(args, format);
- vsnprintf(buffer, sizeof(buffer), format, args);
- va_end(args);
- buffer[sizeof(buffer) - 1] = 0;
- mpack_break_hit(buffer);
-}
-#endif
-
-#if !MPACK_CUSTOM_ASSERT
-void mpack_assert_fail(const char* message) {
- MPACK_UNUSED(message);
-
- #if MPACK_STDIO
- fprintf(stderr, "%s\n", message);
- #endif
-}
-#endif
-
-// We split the assert failure from the wrapper so that a
-// custom assert function can return.
-void mpack_assert_fail_wrapper(const char* message) {
-
- #ifdef MPACK_GCOV
- // gcov marks even __builtin_unreachable() as an uncovered line. this
- // silences it.
- (mpack_assert_fail(message), __builtin_unreachable());
-
- #else
- mpack_assert_fail(message);
-
- // mpack_assert_fail() is not supposed to return. in case it does, we
- // abort.
-
- #if !MPACK_NO_BUILTINS
- #if defined(__GNUC__) || defined(__clang__)
- __builtin_trap();
- #elif defined(WIN32)
- __debugbreak();
- #endif
- #endif
-
- #if (defined(__GNUC__) || defined(__clang__)) && !MPACK_NO_BUILTINS
- __builtin_abort();
- #elif MPACK_STDLIB
- abort();
- #endif
-
- MPACK_UNREACHABLE;
- #endif
-}
-
-#if !MPACK_CUSTOM_BREAK
-
-// If we have a custom assert handler, break wraps it by default.
-// This allows users of MPack to only implement mpack_assert_fail() without
-// having to worry about the difference between assert and break.
-//
-// MPACK_CUSTOM_BREAK is available to define a separate break handler
-// (which is needed by the unit test suite), but this is not offered in
-// mpack-config.h for simplicity.
-
-#if MPACK_CUSTOM_ASSERT
-void mpack_break_hit(const char* message) {
- mpack_assert_fail_wrapper(message);
-}
-#else
-void mpack_break_hit(const char* message) {
- MPACK_UNUSED(message);
-
- #if MPACK_STDIO
- fprintf(stderr, "%s\n", message);
- #endif
-
- #if defined(__GNUC__) || defined(__clang__) && !MPACK_NO_BUILTINS
- __builtin_trap();
- #elif defined(WIN32) && !MPACK_NO_BUILTINS
- __debugbreak();
- #elif MPACK_STDLIB
- abort();
- #endif
-}
-#endif
-
-#endif
-
-#endif
-
-
-
-// The below are adapted from the C wikibook:
-// https://en.wikibooks.org/wiki/C_Programming/Strings
-
-#ifndef mpack_memcmp
-int mpack_memcmp(const void* s1, const void* s2, size_t n) {
- const unsigned char *us1 = (const unsigned char *) s1;
- const unsigned char *us2 = (const unsigned char *) s2;
- while (n-- != 0) {
- if (*us1 != *us2)
- return (*us1 < *us2) ? -1 : +1;
- us1++;
- us2++;
- }
- return 0;
-}
-#endif
-
-#ifndef mpack_memcpy
-void* mpack_memcpy(void* MPACK_RESTRICT s1, const void* MPACK_RESTRICT s2, size_t n) {
- char* MPACK_RESTRICT dst = (char *)s1;
- const char* MPACK_RESTRICT src = (const char *)s2;
- while (n-- != 0)
- *dst++ = *src++;
- return s1;
-}
-#endif
-
-#ifndef mpack_memmove
-void* mpack_memmove(void* s1, const void* s2, size_t n) {
- char *p1 = (char *)s1;
- const char *p2 = (const char *)s2;
- if (p2 < p1 && p1 < p2 + n) {
- p2 += n;
- p1 += n;
- while (n-- != 0)
- *--p1 = *--p2;
- } else
- while (n-- != 0)
- *p1++ = *p2++;
- return s1;
-}
-#endif
-
-#ifndef mpack_memset
-void* mpack_memset(void* s, int c, size_t n) {
- unsigned char *us = (unsigned char *)s;
- unsigned char uc = (unsigned char)c;
- while (n-- != 0)
- *us++ = uc;
- return s;
-}
-#endif
-
-#ifndef mpack_strlen
-size_t mpack_strlen(const char* s) {
- const char* p = s;
- while (*p != '\0')
- p++;
- return (size_t)(p - s);
-}
-#endif
-
-
-
-#if defined(MPACK_MALLOC) && !defined(MPACK_REALLOC)
-void* mpack_realloc(void* old_ptr, size_t used_size, size_t new_size) {
- if (new_size == 0) {
- if (old_ptr)
- MPACK_FREE(old_ptr);
- return NULL;
- }
-
- void* new_ptr = MPACK_MALLOC(new_size);
- if (new_ptr == NULL)
- return NULL;
-
- mpack_memcpy(new_ptr, old_ptr, used_size);
- MPACK_FREE(old_ptr);
- return new_ptr;
-}
-#endif
-
-/* mpack/mpack-common.c.c */
-
-#define MPACK_INTERNAL 1
-
-/* #include "mpack-common.h" */
-
-#if MPACK_DEBUG && MPACK_STDIO
-#include <stdarg.h>
-#endif
-
-const char* mpack_error_to_string(mpack_error_t error) {
- #if MPACK_STRINGS
- switch (error) {
- #define MPACK_ERROR_STRING_CASE(e) case e: return #e
- MPACK_ERROR_STRING_CASE(mpack_ok);
- MPACK_ERROR_STRING_CASE(mpack_error_io);
- MPACK_ERROR_STRING_CASE(mpack_error_invalid);
- MPACK_ERROR_STRING_CASE(mpack_error_unsupported);
- MPACK_ERROR_STRING_CASE(mpack_error_type);
- MPACK_ERROR_STRING_CASE(mpack_error_too_big);
- MPACK_ERROR_STRING_CASE(mpack_error_memory);
- MPACK_ERROR_STRING_CASE(mpack_error_bug);
- MPACK_ERROR_STRING_CASE(mpack_error_data);
- MPACK_ERROR_STRING_CASE(mpack_error_eof);
- #undef MPACK_ERROR_STRING_CASE
- }
- mpack_assert(0, "unrecognized error %i", (int)error);
- return "(unknown mpack_error_t)";
- #else
- MPACK_UNUSED(error);
- return "";
- #endif
-}
-
-const char* mpack_type_to_string(mpack_type_t type) {
- #if MPACK_STRINGS
- switch (type) {
- #define MPACK_TYPE_STRING_CASE(e) case e: return #e
- MPACK_TYPE_STRING_CASE(mpack_type_missing);
- MPACK_TYPE_STRING_CASE(mpack_type_nil);
- MPACK_TYPE_STRING_CASE(mpack_type_bool);
- MPACK_TYPE_STRING_CASE(mpack_type_float);
- MPACK_TYPE_STRING_CASE(mpack_type_double);
- MPACK_TYPE_STRING_CASE(mpack_type_int);
- MPACK_TYPE_STRING_CASE(mpack_type_uint);
- MPACK_TYPE_STRING_CASE(mpack_type_str);
- MPACK_TYPE_STRING_CASE(mpack_type_bin);
- MPACK_TYPE_STRING_CASE(mpack_type_array);
- MPACK_TYPE_STRING_CASE(mpack_type_map);
- #if MPACK_EXTENSIONS
- MPACK_TYPE_STRING_CASE(mpack_type_ext);
- #endif
- #undef MPACK_TYPE_STRING_CASE
- }
- mpack_assert(0, "unrecognized type %i", (int)type);
- return "(unknown mpack_type_t)";
- #else
- MPACK_UNUSED(type);
- return "";
- #endif
-}
-
-int mpack_tag_cmp(mpack_tag_t left, mpack_tag_t right) {
-
- // positive numbers may be stored as int; convert to uint
- if (left.type == mpack_type_int && left.v.i >= 0) {
- left.type = mpack_type_uint;
- left.v.u = (uint64_t)left.v.i;
- }
- if (right.type == mpack_type_int && right.v.i >= 0) {
- right.type = mpack_type_uint;
- right.v.u = (uint64_t)right.v.i;
- }
-
- if (left.type != right.type)
- return ((int)left.type < (int)right.type) ? -1 : 1;
-
- switch (left.type) {
- case mpack_type_missing: // fallthrough
- case mpack_type_nil:
- return 0;
-
- case mpack_type_bool:
- return (int)left.v.b - (int)right.v.b;
-
- case mpack_type_int:
- if (left.v.i == right.v.i)
- return 0;
- return (left.v.i < right.v.i) ? -1 : 1;
-
- case mpack_type_uint:
- if (left.v.u == right.v.u)
- return 0;
- return (left.v.u < right.v.u) ? -1 : 1;
-
- case mpack_type_array:
- case mpack_type_map:
- if (left.v.n == right.v.n)
- return 0;
- return (left.v.n < right.v.n) ? -1 : 1;
-
- case mpack_type_str:
- case mpack_type_bin:
- if (left.v.l == right.v.l)
- return 0;
- return (left.v.l < right.v.l) ? -1 : 1;
-
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- if (left.exttype == right.exttype) {
- if (left.v.l == right.v.l)
- return 0;
- return (left.v.l < right.v.l) ? -1 : 1;
- }
- return (int)left.exttype - (int)right.exttype;
- #endif
-
- // floats should not normally be compared for equality. we compare
- // with memcmp() to silence compiler warnings, but this will return
- // equal if both are NaNs with the same representation (though we may
- // want this, for instance if you are for some bizarre reason using
- // floats as map keys.) i'm not sure what the right thing to
- // do is here. check for NaN first? always return false if the type
- // is float? use operator== and pragmas to silence compiler warning?
- // please send me your suggestions.
- // note also that we don't convert floats to doubles, so when this is
- // used for ordering purposes, all floats are ordered before all
- // doubles.
- case mpack_type_float:
- return mpack_memcmp(&left.v.f, &right.v.f, sizeof(left.v.f));
- case mpack_type_double:
- return mpack_memcmp(&left.v.d, &right.v.d, sizeof(left.v.d));
- }
-
- mpack_assert(0, "unrecognized type %i", (int)left.type);
- return false;
-}
-
-#if MPACK_DEBUG && MPACK_STDIO
-static char mpack_hex_char(uint8_t hex_value) {
- return (hex_value < 10) ? (char)('0' + hex_value) : (char)('a' + (hex_value - 10));
-}
-
-static void mpack_tag_debug_complete_bin_ext(mpack_tag_t tag, size_t string_length, char* buffer, size_t buffer_size,
- const char* prefix, size_t prefix_size)
-{
- // If at any point in this function we run out of space in the buffer, we
- // bail out. The outer tag print wrapper will make sure we have a
- // null-terminator.
-
- if (string_length == 0 || string_length >= buffer_size)
- return;
- buffer += string_length;
- buffer_size -= string_length;
-
- size_t total = mpack_tag_bytes(&tag);
- if (total == 0) {
- strncpy(buffer, ">", buffer_size);
- return;
- }
-
- strncpy(buffer, ": ", buffer_size);
- if (buffer_size < 2)
- return;
- buffer += 2;
- buffer_size -= 2;
-
- size_t hex_bytes = 0;
- for (size_t i = 0; i < MPACK_PRINT_BYTE_COUNT && i < prefix_size && buffer_size > 2; ++i) {
- uint8_t byte = (uint8_t)prefix[i];
- buffer[0] = mpack_hex_char((uint8_t)(byte >> 4));
- buffer[1] = mpack_hex_char((uint8_t)(byte & 0xfu));
- buffer += 2;
- buffer_size -= 2;
- ++hex_bytes;
- }
-
- if (buffer_size != 0)
- mpack_snprintf(buffer, buffer_size, "%s>", (total > hex_bytes) ? "..." : "");
-}
-
-static void mpack_tag_debug_pseudo_json_bin(mpack_tag_t tag, char* buffer, size_t buffer_size,
- const char* prefix, size_t prefix_size)
-{
- mpack_assert(mpack_tag_type(&tag) == mpack_type_bin);
- size_t length = (size_t)mpack_snprintf(buffer, buffer_size, "<binary data of length %u", tag.v.l);
- mpack_tag_debug_complete_bin_ext(tag, length, buffer, buffer_size, prefix, prefix_size);
-}
-
-#if MPACK_EXTENSIONS
-static void mpack_tag_debug_pseudo_json_ext(mpack_tag_t tag, char* buffer, size_t buffer_size,
- const char* prefix, size_t prefix_size)
-{
- mpack_assert(mpack_tag_type(&tag) == mpack_type_ext);
- size_t length = (size_t)mpack_snprintf(buffer, buffer_size, "<ext data of type %i and length %u",
- mpack_tag_ext_exttype(&tag), mpack_tag_ext_length(&tag));
- mpack_tag_debug_complete_bin_ext(tag, length, buffer, buffer_size, prefix, prefix_size);
-}
-#endif
-
-static void mpack_tag_debug_pseudo_json_impl(mpack_tag_t tag, char* buffer, size_t buffer_size,
- const char* prefix, size_t prefix_size)
-{
- switch (tag.type) {
- case mpack_type_missing:
- mpack_snprintf(buffer, buffer_size, "<missing!>");
- return;
- case mpack_type_nil:
- mpack_snprintf(buffer, buffer_size, "null");
- return;
- case mpack_type_bool:
- mpack_snprintf(buffer, buffer_size, tag.v.b ? "true" : "false");
- return;
- case mpack_type_int:
- mpack_snprintf(buffer, buffer_size, "%" PRIi64, tag.v.i);
- return;
- case mpack_type_uint:
- mpack_snprintf(buffer, buffer_size, "%" PRIu64, tag.v.u);
- return;
- case mpack_type_float:
- mpack_snprintf(buffer, buffer_size, "%f", tag.v.f);
- return;
- case mpack_type_double:
- mpack_snprintf(buffer, buffer_size, "%f", tag.v.d);
- return;
-
- case mpack_type_str:
- mpack_snprintf(buffer, buffer_size, "<string of %u bytes>", tag.v.l);
- return;
- case mpack_type_bin:
- mpack_tag_debug_pseudo_json_bin(tag, buffer, buffer_size, prefix, prefix_size);
- return;
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- mpack_tag_debug_pseudo_json_ext(tag, buffer, buffer_size, prefix, prefix_size);
- return;
- #endif
-
- case mpack_type_array:
- mpack_snprintf(buffer, buffer_size, "<array of %u elements>", tag.v.n);
- return;
- case mpack_type_map:
- mpack_snprintf(buffer, buffer_size, "<map of %u key-value pairs>", tag.v.n);
- return;
- }
-
- mpack_snprintf(buffer, buffer_size, "<unknown!>");
-}
-
-void mpack_tag_debug_pseudo_json(mpack_tag_t tag, char* buffer, size_t buffer_size,
- const char* prefix, size_t prefix_size)
-{
- mpack_assert(buffer_size > 0, "buffer size cannot be zero!");
- buffer[0] = 0;
-
- mpack_tag_debug_pseudo_json_impl(tag, buffer, buffer_size, prefix, prefix_size);
-
- // We always null-terminate the buffer manually just in case the snprintf()
- // function doesn't null-terminate when the string doesn't fit.
- buffer[buffer_size - 1] = 0;
-}
-
-static void mpack_tag_debug_describe_impl(mpack_tag_t tag, char* buffer, size_t buffer_size) {
- switch (tag.type) {
- case mpack_type_missing:
- mpack_snprintf(buffer, buffer_size, "missing");
- return;
- case mpack_type_nil:
- mpack_snprintf(buffer, buffer_size, "nil");
- return;
- case mpack_type_bool:
- mpack_snprintf(buffer, buffer_size, tag.v.b ? "true" : "false");
- return;
- case mpack_type_int:
- mpack_snprintf(buffer, buffer_size, "int %" PRIi64, tag.v.i);
- return;
- case mpack_type_uint:
- mpack_snprintf(buffer, buffer_size, "uint %" PRIu64, tag.v.u);
- return;
- case mpack_type_float:
- mpack_snprintf(buffer, buffer_size, "float %f", tag.v.f);
- return;
- case mpack_type_double:
- mpack_snprintf(buffer, buffer_size, "double %f", tag.v.d);
- return;
- case mpack_type_str:
- mpack_snprintf(buffer, buffer_size, "str of %u bytes", tag.v.l);
- return;
- case mpack_type_bin:
- mpack_snprintf(buffer, buffer_size, "bin of %u bytes", tag.v.l);
- return;
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- mpack_snprintf(buffer, buffer_size, "ext of type %i, %u bytes",
- mpack_tag_ext_exttype(&tag), mpack_tag_ext_length(&tag));
- return;
- #endif
- case mpack_type_array:
- mpack_snprintf(buffer, buffer_size, "array of %u elements", tag.v.n);
- return;
- case mpack_type_map:
- mpack_snprintf(buffer, buffer_size, "map of %u key-value pairs", tag.v.n);
- return;
- }
-
- mpack_snprintf(buffer, buffer_size, "unknown!");
-}
-
-void mpack_tag_debug_describe(mpack_tag_t tag, char* buffer, size_t buffer_size) {
- mpack_assert(buffer_size > 0, "buffer size cannot be zero!");
- buffer[0] = 0;
-
- mpack_tag_debug_describe_impl(tag, buffer, buffer_size);
-
- // We always null-terminate the buffer manually just in case the snprintf()
- // function doesn't null-terminate when the string doesn't fit.
- buffer[buffer_size - 1] = 0;
-}
-#endif
-
-
-
-#if MPACK_READ_TRACKING || MPACK_WRITE_TRACKING
-
-#ifndef MPACK_TRACKING_INITIAL_CAPACITY
-// seems like a reasonable number. we grow by doubling, and it only
-// needs to be as long as the maximum depth of the message.
-#define MPACK_TRACKING_INITIAL_CAPACITY 8
-#endif
-
-mpack_error_t mpack_track_init(mpack_track_t* track) {
- track->count = 0;
- track->capacity = MPACK_TRACKING_INITIAL_CAPACITY;
- track->elements = (mpack_track_element_t*)MPACK_MALLOC(sizeof(mpack_track_element_t) * track->capacity);
- if (track->elements == NULL)
- return mpack_error_memory;
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_grow(mpack_track_t* track) {
- mpack_assert(track->elements, "null track elements!");
- mpack_assert(track->count == track->capacity, "incorrect growing?");
-
- size_t new_capacity = track->capacity * 2;
-
- mpack_track_element_t* new_elements = (mpack_track_element_t*)mpack_realloc(track->elements,
- sizeof(mpack_track_element_t) * track->count, sizeof(mpack_track_element_t) * new_capacity);
- if (new_elements == NULL)
- return mpack_error_memory;
-
- track->elements = new_elements;
- track->capacity = new_capacity;
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_push(mpack_track_t* track, mpack_type_t type, uint64_t count) {
- mpack_assert(track->elements, "null track elements!");
- mpack_log("track pushing %s count %i\n", mpack_type_to_string(type), (int)count);
-
- // maps have twice the number of elements (key/value pairs)
- if (type == mpack_type_map)
- count *= 2;
-
- // grow if needed
- if (track->count == track->capacity) {
- mpack_error_t error = mpack_track_grow(track);
- if (error != mpack_ok)
- return error;
- }
-
- // insert new track
- track->elements[track->count].type = type;
- track->elements[track->count].left = count;
- ++track->count;
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_pop(mpack_track_t* track, mpack_type_t type) {
- mpack_assert(track->elements, "null track elements!");
- mpack_log("track popping %s\n", mpack_type_to_string(type));
-
- if (track->count == 0) {
- mpack_break("attempting to close a %s but nothing was opened!", mpack_type_to_string(type));
- return mpack_error_bug;
- }
-
- mpack_track_element_t* element = &track->elements[track->count - 1];
-
- if (element->type != type) {
- mpack_break("attempting to close a %s but the open element is a %s!",
- mpack_type_to_string(type), mpack_type_to_string(element->type));
- return mpack_error_bug;
- }
-
- if (element->left != 0) {
- mpack_break("attempting to close a %s but there are %" PRIu64 " %s left",
- mpack_type_to_string(type), element->left,
- (type == mpack_type_map || type == mpack_type_array) ? "elements" : "bytes");
- return mpack_error_bug;
- }
-
- --track->count;
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_peek_element(mpack_track_t* track, bool read) {
- MPACK_UNUSED(read);
- mpack_assert(track->elements, "null track elements!");
-
- // if there are no open elements, that's fine, we can read/write elements at will
- if (track->count == 0)
- return mpack_ok;
-
- mpack_track_element_t* element = &track->elements[track->count - 1];
-
- if (element->type != mpack_type_map && element->type != mpack_type_array) {
- mpack_break("elements cannot be %s within an %s", read ? "read" : "written",
- mpack_type_to_string(element->type));
- return mpack_error_bug;
- }
-
- if (element->left == 0) {
- mpack_break("too many elements %s for %s", read ? "read" : "written",
- mpack_type_to_string(element->type));
- return mpack_error_bug;
- }
-
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_element(mpack_track_t* track, bool read) {
- mpack_error_t error = mpack_track_peek_element(track, read);
- if (track->count > 0 && error == mpack_ok)
- --track->elements[track->count - 1].left;
- return error;
-}
-
-mpack_error_t mpack_track_bytes(mpack_track_t* track, bool read, uint64_t count) {
- MPACK_UNUSED(read);
- mpack_assert(track->elements, "null track elements!");
-
- if (track->count == 0) {
- mpack_break("bytes cannot be %s with no open bin, str or ext", read ? "read" : "written");
- return mpack_error_bug;
- }
-
- mpack_track_element_t* element = &track->elements[track->count - 1];
-
- if (element->type == mpack_type_map || element->type == mpack_type_array) {
- mpack_break("bytes cannot be %s within an %s", read ? "read" : "written",
- mpack_type_to_string(element->type));
- return mpack_error_bug;
- }
-
- if (element->left < count) {
- mpack_break("too many bytes %s for %s", read ? "read" : "written",
- mpack_type_to_string(element->type));
- return mpack_error_bug;
- }
-
- element->left -= count;
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_str_bytes_all(mpack_track_t* track, bool read, uint64_t count) {
- mpack_error_t error = mpack_track_bytes(track, read, count);
- if (error != mpack_ok)
- return error;
-
- mpack_track_element_t* element = &track->elements[track->count - 1];
-
- if (element->type != mpack_type_str) {
- mpack_break("the open type must be a string, not a %s", mpack_type_to_string(element->type));
- return mpack_error_bug;
- }
-
- if (element->left != 0) {
- mpack_break("not all bytes were read; the wrong byte count was requested for a string read.");
- return mpack_error_bug;
- }
-
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_check_empty(mpack_track_t* track) {
- if (track->count != 0) {
- mpack_break("unclosed %s", mpack_type_to_string(track->elements[0].type));
- return mpack_error_bug;
- }
- return mpack_ok;
-}
-
-mpack_error_t mpack_track_destroy(mpack_track_t* track, bool cancel) {
- mpack_error_t error = cancel ? mpack_ok : mpack_track_check_empty(track);
- if (track->elements) {
- MPACK_FREE(track->elements);
- track->elements = NULL;
- }
- return error;
-}
-#endif
-
-
-
-static bool mpack_utf8_check_impl(const uint8_t* str, size_t count, bool allow_null) {
- while (count > 0) {
- uint8_t lead = str[0];
-
- // NUL
- if (!allow_null && lead == '\0') // we don't allow NUL bytes in MPack C-strings
- return false;
-
- // ASCII
- if (lead <= 0x7F) {
- ++str;
- --count;
-
- // 2-byte sequence
- } else if ((lead & 0xE0) == 0xC0) {
- if (count < 2) // truncated sequence
- return false;
-
- uint8_t cont = str[1];
- if ((cont & 0xC0) != 0x80) // not a continuation byte
- return false;
-
- str += 2;
- count -= 2;
-
- uint32_t z = ((uint32_t)(lead & ~0xE0) << 6) |
- (uint32_t)(cont & ~0xC0);
-
- if (z < 0x80) // overlong sequence
- return false;
-
- // 3-byte sequence
- } else if ((lead & 0xF0) == 0xE0) {
- if (count < 3) // truncated sequence
- return false;
-
- uint8_t cont1 = str[1];
- if ((cont1 & 0xC0) != 0x80) // not a continuation byte
- return false;
- uint8_t cont2 = str[2];
- if ((cont2 & 0xC0) != 0x80) // not a continuation byte
- return false;
-
- str += 3;
- count -= 3;
-
- uint32_t z = ((uint32_t)(lead & ~0xF0) << 12) |
- ((uint32_t)(cont1 & ~0xC0) << 6) |
- (uint32_t)(cont2 & ~0xC0);
-
- if (z < 0x800) // overlong sequence
- return false;
- if (z >= 0xD800 && z <= 0xDFFF) // surrogate
- return false;
-
- // 4-byte sequence
- } else if ((lead & 0xF8) == 0xF0) {
- if (count < 4) // truncated sequence
- return false;
-
- uint8_t cont1 = str[1];
- if ((cont1 & 0xC0) != 0x80) // not a continuation byte
- return false;
- uint8_t cont2 = str[2];
- if ((cont2 & 0xC0) != 0x80) // not a continuation byte
- return false;
- uint8_t cont3 = str[3];
- if ((cont3 & 0xC0) != 0x80) // not a continuation byte
- return false;
-
- str += 4;
- count -= 4;
-
- uint32_t z = ((uint32_t)(lead & ~0xF8) << 18) |
- ((uint32_t)(cont1 & ~0xC0) << 12) |
- ((uint32_t)(cont2 & ~0xC0) << 6) |
- (uint32_t)(cont3 & ~0xC0);
-
- if (z < 0x10000) // overlong sequence
- return false;
- if (z > 0x10FFFF) // codepoint limit
- return false;
-
- } else {
- return false; // continuation byte without a lead, or lead for a 5-byte sequence or longer
- }
- }
- return true;
-}
-
-bool mpack_utf8_check(const char* str, size_t bytes) {
- return mpack_utf8_check_impl((const uint8_t*)str, bytes, true);
-}
-
-bool mpack_utf8_check_no_null(const char* str, size_t bytes) {
- return mpack_utf8_check_impl((const uint8_t*)str, bytes, false);
-}
-
-bool mpack_str_check_no_null(const char* str, size_t bytes) {
- for (size_t i = 0; i < bytes; ++i)
- if (str[i] == '\0')
- return false;
- return true;
-}
-
-#if MPACK_DEBUG && MPACK_STDIO
-void mpack_print_append(mpack_print_t* print, const char* data, size_t count) {
-
- // copy whatever fits into the buffer
- size_t copy = print->size - print->count;
- if (copy > count)
- copy = count;
- mpack_memcpy(print->buffer + print->count, data, copy);
- print->count += copy;
- data += copy;
- count -= copy;
-
- // if we don't need to flush or can't flush there's nothing else to do
- if (count == 0 || print->callback == NULL)
- return;
-
- // flush the buffer
- print->callback(print->context, print->buffer, print->count);
-
- if (count > print->size / 2) {
- // flush the rest of the data
- print->count = 0;
- print->callback(print->context, data, count);
- } else {
- // copy the rest of the data into the buffer
- mpack_memcpy(print->buffer, data, count);
- print->count = count;
- }
-
-}
-
-void mpack_print_flush(mpack_print_t* print) {
- if (print->count > 0 && print->callback != NULL) {
- print->callback(print->context, print->buffer, print->count);
- print->count = 0;
- }
-}
-
-void mpack_print_file_callback(void* context, const char* data, size_t count) {
- FILE* file = (FILE*)context;
- fwrite(data, 1, count, file);
-}
-#endif
-
-/* mpack/mpack-writer.c.c */
-
-#define MPACK_INTERNAL 1
-
-/* #include "mpack-writer.h" */
-
-#if MPACK_WRITER
-
-#if MPACK_WRITE_TRACKING
-static void mpack_writer_flag_if_error(mpack_writer_t* writer, mpack_error_t error) {
- if (error != mpack_ok)
- mpack_writer_flag_error(writer, error);
-}
-
-void mpack_writer_track_push(mpack_writer_t* writer, mpack_type_t type, uint64_t count) {
- if (writer->error == mpack_ok)
- mpack_writer_flag_if_error(writer, mpack_track_push(&writer->track, type, count));
-}
-
-void mpack_writer_track_pop(mpack_writer_t* writer, mpack_type_t type) {
- if (writer->error == mpack_ok)
- mpack_writer_flag_if_error(writer, mpack_track_pop(&writer->track, type));
-}
-
-void mpack_writer_track_element(mpack_writer_t* writer) {
- if (writer->error == mpack_ok)
- mpack_writer_flag_if_error(writer, mpack_track_element(&writer->track, false));
-}
-
-void mpack_writer_track_bytes(mpack_writer_t* writer, size_t count) {
- if (writer->error == mpack_ok)
- mpack_writer_flag_if_error(writer, mpack_track_bytes(&writer->track, false, count));
-}
-#endif
-
-static void mpack_writer_clear(mpack_writer_t* writer) {
- #if MPACK_COMPATIBILITY
- writer->version = mpack_version_current;
- #endif
- writer->flush = NULL;
- writer->error_fn = NULL;
- writer->teardown = NULL;
- writer->context = NULL;
-
- writer->buffer = NULL;
- writer->current = NULL;
- writer->end = NULL;
- writer->error = mpack_ok;
-
- #if MPACK_WRITE_TRACKING
- mpack_memset(&writer->track, 0, sizeof(writer->track));
- #endif
-}
-
-void mpack_writer_init(mpack_writer_t* writer, char* buffer, size_t size) {
- mpack_assert(buffer != NULL, "cannot initialize writer with empty buffer");
- mpack_writer_clear(writer);
- writer->buffer = buffer;
- writer->current = buffer;
- writer->end = writer->buffer + size;
-
- #if MPACK_WRITE_TRACKING
- mpack_writer_flag_if_error(writer, mpack_track_init(&writer->track));
- #endif
-
- mpack_log("===========================\n");
- mpack_log("initializing writer with buffer size %i\n", (int)size);
-}
-
-void mpack_writer_init_error(mpack_writer_t* writer, mpack_error_t error) {
- mpack_writer_clear(writer);
- writer->error = error;
-
- mpack_log("===========================\n");
- mpack_log("initializing writer in error state %i\n", (int)error);
-}
-
-void mpack_writer_set_flush(mpack_writer_t* writer, mpack_writer_flush_t flush) {
- MPACK_STATIC_ASSERT(MPACK_WRITER_MINIMUM_BUFFER_SIZE >= MPACK_MAXIMUM_TAG_SIZE,
- "minimum buffer size must fit any tag!");
- MPACK_STATIC_ASSERT(31 + MPACK_TAG_SIZE_FIXSTR >= MPACK_WRITER_MINIMUM_BUFFER_SIZE,
- "minimum buffer size must fit the largest possible fixstr!");
-
- if (mpack_writer_buffer_size(writer) < MPACK_WRITER_MINIMUM_BUFFER_SIZE) {
- mpack_break("buffer size is %i, but minimum buffer size for flush is %i",
- (int)mpack_writer_buffer_size(writer), MPACK_WRITER_MINIMUM_BUFFER_SIZE);
- mpack_writer_flag_error(writer, mpack_error_bug);
- return;
- }
-
- writer->flush = flush;
-}
-
-#ifdef MPACK_MALLOC
-typedef struct mpack_growable_writer_t {
- char** target_data;
- size_t* target_size;
-} mpack_growable_writer_t;
-
-static char* mpack_writer_get_reserved(mpack_writer_t* writer) {
- // This is in a separate function in order to avoid false strict aliasing
- // warnings. We aren't actually violating strict aliasing (the reserved
- // space is only ever dereferenced as an mpack_growable_writer_t.)
- return (char*)writer->reserved;
-}
-
-static void mpack_growable_writer_flush(mpack_writer_t* writer, const char* data, size_t count) {
-
- // This is an intrusive flush function which modifies the writer's buffer
- // in response to a flush instead of emptying it in order to add more
- // capacity for data. This removes the need to copy data from a fixed buffer
- // into a growable one, improving performance.
- //
- // There are three ways flush can be called:
- // - flushing the buffer during writing (used is zero, count is all data, data is buffer)
- // - flushing extra data during writing (used is all flushed data, count is extra data, data is not buffer)
- // - flushing during teardown (used and count are both all flushed data, data is buffer)
- //
- // In the first two cases, we grow the buffer by at least double, enough
- // to ensure that new data will fit. We ignore the teardown flush.
-
- if (data == writer->buffer) {
-
- // teardown, do nothing
- if (mpack_writer_buffer_used(writer) == count)
- return;
-
- // otherwise leave the data in the buffer and just grow
- writer->current = writer->buffer + count;
- count = 0;
- }
-
- size_t used = mpack_writer_buffer_used(writer);
- size_t size = mpack_writer_buffer_size(writer);
-
- mpack_log("flush size %i used %i data %p buffer %p\n",
- (int)count, (int)used, data, writer->buffer);
-
- mpack_assert(data == writer->buffer || used + count > size,
- "extra flush for %i but there is %i space left in the buffer! (%i/%i)",
- (int)count, (int)mpack_writer_buffer_left(writer), (int)used, (int)size);
-
- // grow to fit the data
- // TODO: this really needs to correctly test for overflow
- size_t new_size = size * 2;
- while (new_size < used + count)
- new_size *= 2;
-
- mpack_log("flush growing buffer size from %i to %i\n", (int)size, (int)new_size);
-
- // grow the buffer
- char* new_buffer = (char*)mpack_realloc(writer->buffer, used, new_size);
- if (new_buffer == NULL) {
- mpack_writer_flag_error(writer, mpack_error_memory);
- return;
- }
- writer->current = new_buffer + used;
- writer->buffer = new_buffer;
- writer->end = writer->buffer + new_size;
-
- // append the extra data
- if (count > 0) {
- mpack_memcpy(writer->current, data, count);
- writer->current += count;
- }
-
- mpack_log("new buffer %p, used %i\n", new_buffer, (int)mpack_writer_buffer_used(writer));
-}
-
-static void mpack_growable_writer_teardown(mpack_writer_t* writer) {
- mpack_growable_writer_t* growable_writer = (mpack_growable_writer_t*)mpack_writer_get_reserved(writer);
-
- if (mpack_writer_error(writer) == mpack_ok) {
-
- // shrink the buffer to an appropriate size if the data is
- // much smaller than the buffer
- if (mpack_writer_buffer_used(writer) < mpack_writer_buffer_size(writer) / 2) {
- size_t used = mpack_writer_buffer_used(writer);
-
- // We always return a non-null pointer that must be freed, even if
- // nothing was written. malloc() and realloc() do not necessarily
- // do this so we enforce it ourselves.
- size_t size = (used != 0) ? used : 1;
-
- char* buffer = (char*)mpack_realloc(writer->buffer, used, size);
- if (!buffer) {
- MPACK_FREE(writer->buffer);
- mpack_writer_flag_error(writer, mpack_error_memory);
- return;
- }
- writer->buffer = buffer;
- writer->end = (writer->current = writer->buffer + used);
- }
-
- *growable_writer->target_data = writer->buffer;
- *growable_writer->target_size = mpack_writer_buffer_used(writer);
- writer->buffer = NULL;
-
- } else if (writer->buffer) {
- MPACK_FREE(writer->buffer);
- writer->buffer = NULL;
- }
-
- writer->context = NULL;
-}
-
-void mpack_writer_init_growable(mpack_writer_t* writer, char** target_data, size_t* target_size) {
- mpack_assert(target_data != NULL, "cannot initialize writer without a destination for the data");
- mpack_assert(target_size != NULL, "cannot initialize writer without a destination for the size");
-
- *target_data = NULL;
- *target_size = 0;
-
- MPACK_STATIC_ASSERT(sizeof(mpack_growable_writer_t) <= sizeof(writer->reserved),
- "not enough reserved space for growable writer!");
- mpack_growable_writer_t* growable_writer = (mpack_growable_writer_t*)mpack_writer_get_reserved(writer);
-
- growable_writer->target_data = target_data;
- growable_writer->target_size = target_size;
-
- size_t capacity = MPACK_BUFFER_SIZE;
- char* buffer = (char*)MPACK_MALLOC(capacity);
- if (buffer == NULL) {
- mpack_writer_init_error(writer, mpack_error_memory);
- return;
- }
-
- mpack_writer_init(writer, buffer, capacity);
- mpack_writer_set_flush(writer, mpack_growable_writer_flush);
- mpack_writer_set_teardown(writer, mpack_growable_writer_teardown);
-}
-#endif
-
-#if MPACK_STDIO
-static void mpack_file_writer_flush(mpack_writer_t* writer, const char* buffer, size_t count) {
- FILE* file = (FILE*)writer->context;
- size_t written = fwrite((const void*)buffer, 1, count, file);
- if (written != count)
- mpack_writer_flag_error(writer, mpack_error_io);
-}
-
-static void mpack_file_writer_teardown(mpack_writer_t* writer) {
- MPACK_FREE(writer->buffer);
- writer->buffer = NULL;
- writer->context = NULL;
-}
-
-static void mpack_file_writer_teardown_close(mpack_writer_t* writer) {
- FILE* file = (FILE*)writer->context;
-
- if (file) {
- int ret = fclose(file);
- if (ret != 0)
- mpack_writer_flag_error(writer, mpack_error_io);
- }
-
- mpack_file_writer_teardown(writer);
-}
-
-void mpack_writer_init_stdfile(mpack_writer_t* writer, FILE* file, bool close_when_done) {
- mpack_assert(file != NULL, "file is NULL");
-
- size_t capacity = MPACK_BUFFER_SIZE;
- char* buffer = (char*)MPACK_MALLOC(capacity);
- if (buffer == NULL) {
- mpack_writer_init_error(writer, mpack_error_memory);
- if (close_when_done) {
- fclose(file);
- }
- return;
- }
-
- mpack_writer_init(writer, buffer, capacity);
- mpack_writer_set_context(writer, file);
- mpack_writer_set_flush(writer, mpack_file_writer_flush);
- mpack_writer_set_teardown(writer, close_when_done ?
- mpack_file_writer_teardown_close :
- mpack_file_writer_teardown);
-}
-
-void mpack_writer_init_filename(mpack_writer_t* writer, const char* filename) {
- mpack_assert(filename != NULL, "filename is NULL");
-
- FILE* file = fopen(filename, "wb");
- if (file == NULL) {
- mpack_writer_init_error(writer, mpack_error_io);
- return;
- }
-
- mpack_writer_init_stdfile(writer, file, true);
-}
-#endif
-
-void mpack_writer_flag_error(mpack_writer_t* writer, mpack_error_t error) {
- mpack_log("writer %p setting error %i: %s\n", writer, (int)error, mpack_error_to_string(error));
-
- if (writer->error == mpack_ok) {
- writer->error = error;
- if (writer->error_fn)
- writer->error_fn(writer, writer->error);
- }
-}
-
-MPACK_STATIC_INLINE void mpack_writer_flush_unchecked(mpack_writer_t* writer) {
- // This is a bit ugly; we reset used before calling flush so that
- // a flush function can distinguish between flushing the buffer
- // versus flushing external data. see mpack_growable_writer_flush()
- size_t used = mpack_writer_buffer_used(writer);
- writer->current = writer->buffer;
- writer->flush(writer, writer->buffer, used);
-}
-
-void mpack_writer_flush_message(mpack_writer_t* writer) {
- if (writer->error != mpack_ok)
- return;
-
- #if MPACK_WRITE_TRACKING
- mpack_writer_flag_if_error(writer, mpack_track_check_empty(&writer->track));
- if (writer->error != mpack_ok)
- return;
- #endif
-
- if (writer->flush == NULL) {
- mpack_break("cannot call mpack_writer_flush_message() without a flush function!");
- mpack_writer_flag_error(writer, mpack_error_bug);
- return;
- }
-
- if (mpack_writer_buffer_used(writer) > 0)
- mpack_writer_flush_unchecked(writer);
-}
-
-// Ensures there are at least count bytes free in the buffer. This
-// will flag an error if the flush function fails to make enough
-// room in the buffer.
-MPACK_NOINLINE static bool mpack_writer_ensure(mpack_writer_t* writer, size_t count) {
- mpack_assert(count != 0, "cannot ensure zero bytes!");
- mpack_assert(count <= MPACK_WRITER_MINIMUM_BUFFER_SIZE,
- "cannot ensure %i bytes, this is more than the minimum buffer size %i!",
- (int)count, (int)MPACK_WRITER_MINIMUM_BUFFER_SIZE);
- mpack_assert(count > mpack_writer_buffer_left(writer),
- "request to ensure %i bytes but there are already %i left in the buffer!",
- (int)count, (int)mpack_writer_buffer_left(writer));
-
- mpack_log("ensuring %i bytes, %i left\n", (int)count, (int)mpack_writer_buffer_left(writer));
-
- if (mpack_writer_error(writer) != mpack_ok)
- return false;
-
- if (writer->flush == NULL) {
- mpack_writer_flag_error(writer, mpack_error_too_big);
- return false;
- }
-
- mpack_writer_flush_unchecked(writer);
- if (mpack_writer_error(writer) != mpack_ok)
- return false;
-
- if (mpack_writer_buffer_left(writer) >= count)
- return true;
-
- mpack_writer_flag_error(writer, mpack_error_io);
- return false;
-}
-
-// Writes encoded bytes to the buffer when we already know the data
-// does not fit in the buffer (i.e. it straddles the edge of the
-// buffer.) If there is a flush function, it is guaranteed to be
-// called; otherwise mpack_error_too_big is raised.
-MPACK_NOINLINE static void mpack_write_native_straddle(mpack_writer_t* writer, const char* p, size_t count) {
- mpack_assert(count == 0 || p != NULL, "data pointer for %i bytes is NULL", (int)count);
-
- if (mpack_writer_error(writer) != mpack_ok)
- return;
- mpack_log("big write for %i bytes from %p, %i space left in buffer\n",
- (int)count, p, (int)mpack_writer_buffer_left(writer));
- mpack_assert(count > mpack_writer_buffer_left(writer),
- "big write requested for %i bytes, but there is %i available "
- "space in buffer. should have called mpack_write_native() instead",
- (int)count, (int)(mpack_writer_buffer_left(writer)));
-
- // we'll need a flush function
- if (!writer->flush) {
- mpack_writer_flag_error(writer, mpack_error_too_big);
- return;
- }
-
- // flush the buffer
- mpack_writer_flush_unchecked(writer);
- if (mpack_writer_error(writer) != mpack_ok)
- return;
-
- // note that an intrusive flush function (such as mpack_growable_writer_flush())
- // may have changed size and/or reset used to a non-zero value. we treat both as
- // though they may have changed, and there may still be data in the buffer.
-
- // flush the extra data directly if it doesn't fit in the buffer
- if (count > mpack_writer_buffer_left(writer)) {
- writer->flush(writer, p, count);
- if (mpack_writer_error(writer) != mpack_ok)
- return;
- } else {
- mpack_memcpy(writer->current, p, count);
- writer->current += count;
- }
-}
-
-// Writes encoded bytes to the buffer, flushing if necessary.
-MPACK_STATIC_INLINE void mpack_write_native(mpack_writer_t* writer, const char* p, size_t count) {
- mpack_assert(count == 0 || p != NULL, "data pointer for %i bytes is NULL", (int)count);
-
- if (mpack_writer_buffer_left(writer) < count) {
- mpack_write_native_straddle(writer, p, count);
- } else {
- mpack_memcpy(writer->current, p, count);
- writer->current += count;
- }
-}
-
-mpack_error_t mpack_writer_destroy(mpack_writer_t* writer) {
-
- // clean up tracking, asserting if we're not already in an error state
- #if MPACK_WRITE_TRACKING
- mpack_track_destroy(&writer->track, writer->error != mpack_ok);
- #endif
-
- // flush any outstanding data
- if (mpack_writer_error(writer) == mpack_ok && mpack_writer_buffer_used(writer) != 0 && writer->flush != NULL) {
- writer->flush(writer, writer->buffer, mpack_writer_buffer_used(writer));
- writer->flush = NULL;
- }
-
- if (writer->teardown) {
- writer->teardown(writer);
- writer->teardown = NULL;
- }
-
- return writer->error;
-}
-
-void mpack_write_tag(mpack_writer_t* writer, mpack_tag_t value) {
- switch (value.type) {
- case mpack_type_missing:
- mpack_break("cannot write a missing value!");
- mpack_writer_flag_error(writer, mpack_error_bug);
- return;
-
- case mpack_type_nil: mpack_write_nil (writer); return;
- case mpack_type_bool: mpack_write_bool (writer, value.v.b); return;
- case mpack_type_float: mpack_write_float (writer, value.v.f); return;
- case mpack_type_double: mpack_write_double(writer, value.v.d); return;
- case mpack_type_int: mpack_write_int (writer, value.v.i); return;
- case mpack_type_uint: mpack_write_uint (writer, value.v.u); return;
-
- case mpack_type_str: mpack_start_str(writer, value.v.l); return;
- case mpack_type_bin: mpack_start_bin(writer, value.v.l); return;
-
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- mpack_start_ext(writer, mpack_tag_ext_exttype(&value), mpack_tag_ext_length(&value));
- return;
- #endif
-
- case mpack_type_array: mpack_start_array(writer, value.v.n); return;
- case mpack_type_map: mpack_start_map(writer, value.v.n); return;
- }
-
- mpack_break("unrecognized type %i", (int)value.type);
- mpack_writer_flag_error(writer, mpack_error_bug);
-}
-
-MPACK_STATIC_INLINE void mpack_write_byte_element(mpack_writer_t* writer, char value) {
- mpack_writer_track_element(writer);
- if (MPACK_LIKELY(mpack_writer_buffer_left(writer) >= 1) || mpack_writer_ensure(writer, 1))
- *(writer->current++) = value;
-}
-
-void mpack_write_nil(mpack_writer_t* writer) {
- mpack_write_byte_element(writer, (char)0xc0);
-}
-
-void mpack_write_bool(mpack_writer_t* writer, bool value) {
- mpack_write_byte_element(writer, (char)(0xc2 | (value ? 1 : 0)));
-}
-
-void mpack_write_true(mpack_writer_t* writer) {
- mpack_write_byte_element(writer, (char)0xc3);
-}
-
-void mpack_write_false(mpack_writer_t* writer) {
- mpack_write_byte_element(writer, (char)0xc2);
-}
-
-void mpack_write_object_bytes(mpack_writer_t* writer, const char* data, size_t bytes) {
- mpack_writer_track_element(writer);
- mpack_write_native(writer, data, bytes);
-}
-
-/*
- * Encode functions
- */
-
-MPACK_STATIC_INLINE void mpack_encode_fixuint(char* p, uint8_t value) {
- mpack_assert(value <= 127);
- mpack_store_u8(p, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_u8(char* p, uint8_t value) {
- mpack_assert(value > 127);
- mpack_store_u8(p, 0xcc);
- mpack_store_u8(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_u16(char* p, uint16_t value) {
- mpack_assert(value > UINT8_MAX);
- mpack_store_u8(p, 0xcd);
- mpack_store_u16(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_u32(char* p, uint32_t value) {
- mpack_assert(value > UINT16_MAX);
- mpack_store_u8(p, 0xce);
- mpack_store_u32(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_u64(char* p, uint64_t value) {
- mpack_assert(value > UINT32_MAX);
- mpack_store_u8(p, 0xcf);
- mpack_store_u64(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixint(char* p, int8_t value) {
- // this can encode positive or negative fixints
- mpack_assert(value >= -32);
- mpack_store_i8(p, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_i8(char* p, int8_t value) {
- mpack_assert(value < -32);
- mpack_store_u8(p, 0xd0);
- mpack_store_i8(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_i16(char* p, int16_t value) {
- mpack_assert(value < INT8_MIN);
- mpack_store_u8(p, 0xd1);
- mpack_store_i16(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_i32(char* p, int32_t value) {
- mpack_assert(value < INT16_MIN);
- mpack_store_u8(p, 0xd2);
- mpack_store_i32(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_i64(char* p, int64_t value) {
- mpack_assert(value < INT32_MIN);
- mpack_store_u8(p, 0xd3);
- mpack_store_i64(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_float(char* p, float value) {
- mpack_store_u8(p, 0xca);
- mpack_store_float(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_double(char* p, double value) {
- mpack_store_u8(p, 0xcb);
- mpack_store_double(p + 1, value);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixarray(char* p, uint8_t count) {
- mpack_assert(count <= 15);
- mpack_store_u8(p, (uint8_t)(0x90 | count));
-}
-
-MPACK_STATIC_INLINE void mpack_encode_array16(char* p, uint16_t count) {
- mpack_assert(count > 15);
- mpack_store_u8(p, 0xdc);
- mpack_store_u16(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_array32(char* p, uint32_t count) {
- mpack_assert(count > UINT16_MAX);
- mpack_store_u8(p, 0xdd);
- mpack_store_u32(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixmap(char* p, uint8_t count) {
- mpack_assert(count <= 15);
- mpack_store_u8(p, (uint8_t)(0x80 | count));
-}
-
-MPACK_STATIC_INLINE void mpack_encode_map16(char* p, uint16_t count) {
- mpack_assert(count > 15);
- mpack_store_u8(p, 0xde);
- mpack_store_u16(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_map32(char* p, uint32_t count) {
- mpack_assert(count > UINT16_MAX);
- mpack_store_u8(p, 0xdf);
- mpack_store_u32(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixstr(char* p, uint8_t count) {
- mpack_assert(count <= 31);
- mpack_store_u8(p, (uint8_t)(0xa0 | count));
-}
-
-MPACK_STATIC_INLINE void mpack_encode_str8(char* p, uint8_t count) {
- mpack_assert(count > 31);
- mpack_store_u8(p, 0xd9);
- mpack_store_u8(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_str16(char* p, uint16_t count) {
- // we might be encoding a raw in compatibility mode, so we
- // allow count to be in the range [32, UINT8_MAX].
- mpack_assert(count > 31);
- mpack_store_u8(p, 0xda);
- mpack_store_u16(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_str32(char* p, uint32_t count) {
- mpack_assert(count > UINT16_MAX);
- mpack_store_u8(p, 0xdb);
- mpack_store_u32(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_bin8(char* p, uint8_t count) {
- mpack_store_u8(p, 0xc4);
- mpack_store_u8(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_bin16(char* p, uint16_t count) {
- mpack_assert(count > UINT8_MAX);
- mpack_store_u8(p, 0xc5);
- mpack_store_u16(p + 1, count);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_bin32(char* p, uint32_t count) {
- mpack_assert(count > UINT16_MAX);
- mpack_store_u8(p, 0xc6);
- mpack_store_u32(p + 1, count);
-}
-
-#if MPACK_EXTENSIONS
-MPACK_STATIC_INLINE void mpack_encode_fixext1(char* p, int8_t exttype) {
- mpack_store_u8(p, 0xd4);
- mpack_store_i8(p + 1, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixext2(char* p, int8_t exttype) {
- mpack_store_u8(p, 0xd5);
- mpack_store_i8(p + 1, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixext4(char* p, int8_t exttype) {
- mpack_store_u8(p, 0xd6);
- mpack_store_i8(p + 1, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixext8(char* p, int8_t exttype) {
- mpack_store_u8(p, 0xd7);
- mpack_store_i8(p + 1, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_fixext16(char* p, int8_t exttype) {
- mpack_store_u8(p, 0xd8);
- mpack_store_i8(p + 1, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_ext8(char* p, int8_t exttype, uint8_t count) {
- mpack_assert(count != 1 && count != 2 && count != 4 && count != 8 && count != 16);
- mpack_store_u8(p, 0xc7);
- mpack_store_u8(p + 1, count);
- mpack_store_i8(p + 2, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_ext16(char* p, int8_t exttype, uint16_t count) {
- mpack_assert(count > UINT8_MAX);
- mpack_store_u8(p, 0xc8);
- mpack_store_u16(p + 1, count);
- mpack_store_i8(p + 3, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_ext32(char* p, int8_t exttype, uint32_t count) {
- mpack_assert(count > UINT16_MAX);
- mpack_store_u8(p, 0xc9);
- mpack_store_u32(p + 1, count);
- mpack_store_i8(p + 5, exttype);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_timestamp_4(char* p, uint32_t seconds) {
- mpack_encode_fixext4(p, MPACK_EXTTYPE_TIMESTAMP);
- mpack_store_u32(p + MPACK_TAG_SIZE_FIXEXT4, seconds);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_timestamp_8(char* p, int64_t seconds, uint32_t nanoseconds) {
- mpack_assert(nanoseconds <= MPACK_TIMESTAMP_NANOSECONDS_MAX);
- mpack_encode_fixext8(p, MPACK_EXTTYPE_TIMESTAMP);
- uint64_t encoded = ((uint64_t)nanoseconds << 34) | (uint64_t)seconds;
- mpack_store_u64(p + MPACK_TAG_SIZE_FIXEXT8, encoded);
-}
-
-MPACK_STATIC_INLINE void mpack_encode_timestamp_12(char* p, int64_t seconds, uint32_t nanoseconds) {
- mpack_assert(nanoseconds <= MPACK_TIMESTAMP_NANOSECONDS_MAX);
- mpack_encode_ext8(p, MPACK_EXTTYPE_TIMESTAMP, 12);
- mpack_store_u32(p + MPACK_TAG_SIZE_EXT8, nanoseconds);
- mpack_store_i64(p + MPACK_TAG_SIZE_EXT8 + 4, seconds);
-}
-#endif
-
-
-
-/*
- * Write functions
- */
-
-// This is a macro wrapper to the encode functions to encode
-// directly into the buffer. If mpack_writer_ensure() fails
-// it will flag an error so we don't have to do anything.
-#define MPACK_WRITE_ENCODED(encode_fn, size, ...) do { \
- if (MPACK_LIKELY(mpack_writer_buffer_left(writer) >= size) || mpack_writer_ensure(writer, size)) { \
- MPACK_EXPAND(encode_fn(writer->current, __VA_ARGS__)); \
- writer->current += size; \
- } \
-} while (0)
-
-void mpack_write_u8(mpack_writer_t* writer, uint8_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_write_u64(writer, value);
- #else
- mpack_writer_track_element(writer);
- if (value <= 127) {
- MPACK_WRITE_ENCODED(mpack_encode_fixuint, MPACK_TAG_SIZE_FIXUINT, value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, value);
- }
- #endif
-}
-
-void mpack_write_u16(mpack_writer_t* writer, uint16_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_write_u64(writer, value);
- #else
- mpack_writer_track_element(writer);
- if (value <= 127) {
- MPACK_WRITE_ENCODED(mpack_encode_fixuint, MPACK_TAG_SIZE_FIXUINT, (uint8_t)value);
- } else if (value <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, (uint8_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u16, MPACK_TAG_SIZE_U16, value);
- }
- #endif
-}
-
-void mpack_write_u32(mpack_writer_t* writer, uint32_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_write_u64(writer, value);
- #else
- mpack_writer_track_element(writer);
- if (value <= 127) {
- MPACK_WRITE_ENCODED(mpack_encode_fixuint, MPACK_TAG_SIZE_FIXUINT, (uint8_t)value);
- } else if (value <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, (uint8_t)value);
- } else if (value <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u16, MPACK_TAG_SIZE_U16, (uint16_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u32, MPACK_TAG_SIZE_U32, value);
- }
- #endif
-}
-
-void mpack_write_u64(mpack_writer_t* writer, uint64_t value) {
- mpack_writer_track_element(writer);
-
- if (value <= 127) {
- MPACK_WRITE_ENCODED(mpack_encode_fixuint, MPACK_TAG_SIZE_FIXUINT, (uint8_t)value);
- } else if (value <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, (uint8_t)value);
- } else if (value <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u16, MPACK_TAG_SIZE_U16, (uint16_t)value);
- } else if (value <= UINT32_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u32, MPACK_TAG_SIZE_U32, (uint32_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u64, MPACK_TAG_SIZE_U64, value);
- }
-}
-
-void mpack_write_i8(mpack_writer_t* writer, int8_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_write_i64(writer, value);
- #else
- mpack_writer_track_element(writer);
- if (value >= -32) {
- // we encode positive and negative fixints together
- MPACK_WRITE_ENCODED(mpack_encode_fixint, MPACK_TAG_SIZE_FIXINT, (int8_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_i8, MPACK_TAG_SIZE_I8, (int8_t)value);
- }
- #endif
-}
-
-void mpack_write_i16(mpack_writer_t* writer, int16_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_write_i64(writer, value);
- #else
- mpack_writer_track_element(writer);
- if (value >= -32) {
- if (value <= 127) {
- // we encode positive and negative fixints together
- MPACK_WRITE_ENCODED(mpack_encode_fixint, MPACK_TAG_SIZE_FIXINT, (int8_t)value);
- } else if (value <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, (uint8_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u16, MPACK_TAG_SIZE_U16, (uint16_t)value);
- }
- } else if (value >= INT8_MIN) {
- MPACK_WRITE_ENCODED(mpack_encode_i8, MPACK_TAG_SIZE_I8, (int8_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_i16, MPACK_TAG_SIZE_I16, (int16_t)value);
- }
- #endif
-}
-
-void mpack_write_i32(mpack_writer_t* writer, int32_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_write_i64(writer, value);
- #else
- mpack_writer_track_element(writer);
- if (value >= -32) {
- if (value <= 127) {
- // we encode positive and negative fixints together
- MPACK_WRITE_ENCODED(mpack_encode_fixint, MPACK_TAG_SIZE_FIXINT, (int8_t)value);
- } else if (value <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, (uint8_t)value);
- } else if (value <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u16, MPACK_TAG_SIZE_U16, (uint16_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u32, MPACK_TAG_SIZE_U32, (uint32_t)value);
- }
- } else if (value >= INT8_MIN) {
- MPACK_WRITE_ENCODED(mpack_encode_i8, MPACK_TAG_SIZE_I8, (int8_t)value);
- } else if (value >= INT16_MIN) {
- MPACK_WRITE_ENCODED(mpack_encode_i16, MPACK_TAG_SIZE_I16, (int16_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_i32, MPACK_TAG_SIZE_I32, value);
- }
- #endif
-}
-
-void mpack_write_i64(mpack_writer_t* writer, int64_t value) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- if (value > 127) {
- // for non-fix positive ints we call the u64 writer to save space
- mpack_write_u64(writer, (uint64_t)value);
- return;
- }
- #endif
-
- mpack_writer_track_element(writer);
- if (value >= -32) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- MPACK_WRITE_ENCODED(mpack_encode_fixint, MPACK_TAG_SIZE_FIXINT, (int8_t)value);
- #else
- if (value <= 127) {
- MPACK_WRITE_ENCODED(mpack_encode_fixint, MPACK_TAG_SIZE_FIXINT, (int8_t)value);
- } else if (value <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u8, MPACK_TAG_SIZE_U8, (uint8_t)value);
- } else if (value <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u16, MPACK_TAG_SIZE_U16, (uint16_t)value);
- } else if (value <= UINT32_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_u32, MPACK_TAG_SIZE_U32, (uint32_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_u64, MPACK_TAG_SIZE_U64, (uint64_t)value);
- }
- #endif
- } else if (value >= INT8_MIN) {
- MPACK_WRITE_ENCODED(mpack_encode_i8, MPACK_TAG_SIZE_I8, (int8_t)value);
- } else if (value >= INT16_MIN) {
- MPACK_WRITE_ENCODED(mpack_encode_i16, MPACK_TAG_SIZE_I16, (int16_t)value);
- } else if (value >= INT32_MIN) {
- MPACK_WRITE_ENCODED(mpack_encode_i32, MPACK_TAG_SIZE_I32, (int32_t)value);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_i64, MPACK_TAG_SIZE_I64, value);
- }
-}
-
-void mpack_write_float(mpack_writer_t* writer, float value) {
- mpack_writer_track_element(writer);
- MPACK_WRITE_ENCODED(mpack_encode_float, MPACK_TAG_SIZE_FLOAT, value);
-}
-
-void mpack_write_double(mpack_writer_t* writer, double value) {
- mpack_writer_track_element(writer);
- MPACK_WRITE_ENCODED(mpack_encode_double, MPACK_TAG_SIZE_DOUBLE, value);
-}
-
-#if MPACK_EXTENSIONS
-void mpack_write_timestamp(mpack_writer_t* writer, int64_t seconds, uint32_t nanoseconds) {
- #if MPACK_COMPATIBILITY
- if (writer->version <= mpack_version_v4) {
- mpack_break("Timestamps require spec version v5 or later. This writer is in v%i mode.", (int)writer->version);
- mpack_writer_flag_error(writer, mpack_error_bug);
- return;
- }
- #endif
-
- if (nanoseconds > MPACK_TIMESTAMP_NANOSECONDS_MAX) {
- mpack_break("timestamp nanoseconds out of bounds: %u", nanoseconds);
- mpack_writer_flag_error(writer, mpack_error_bug);
- return;
- }
-
- mpack_writer_track_element(writer);
-
- if (seconds < 0 || seconds >= (INT64_C(1) << 34)) {
- MPACK_WRITE_ENCODED(mpack_encode_timestamp_12, MPACK_EXT_SIZE_TIMESTAMP12, seconds, nanoseconds);
- } else if (seconds > UINT32_MAX || nanoseconds > 0) {
- MPACK_WRITE_ENCODED(mpack_encode_timestamp_8, MPACK_EXT_SIZE_TIMESTAMP8, seconds, nanoseconds);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_timestamp_4, MPACK_EXT_SIZE_TIMESTAMP4, (uint32_t)seconds);
- }
-}
-#endif
-
-void mpack_start_array(mpack_writer_t* writer, uint32_t count) {
- mpack_writer_track_element(writer);
-
- if (count <= 15) {
- MPACK_WRITE_ENCODED(mpack_encode_fixarray, MPACK_TAG_SIZE_FIXARRAY, (uint8_t)count);
- } else if (count <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_array16, MPACK_TAG_SIZE_ARRAY16, (uint16_t)count);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_array32, MPACK_TAG_SIZE_ARRAY32, (uint32_t)count);
- }
-
- mpack_writer_track_push(writer, mpack_type_array, count);
-}
-
-void mpack_start_map(mpack_writer_t* writer, uint32_t count) {
- mpack_writer_track_element(writer);
-
- if (count <= 15) {
- MPACK_WRITE_ENCODED(mpack_encode_fixmap, MPACK_TAG_SIZE_FIXMAP, (uint8_t)count);
- } else if (count <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_map16, MPACK_TAG_SIZE_MAP16, (uint16_t)count);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_map32, MPACK_TAG_SIZE_MAP32, (uint32_t)count);
- }
-
- mpack_writer_track_push(writer, mpack_type_map, count);
-}
-
-static void mpack_start_str_notrack(mpack_writer_t* writer, uint32_t count) {
- if (count <= 31) {
- MPACK_WRITE_ENCODED(mpack_encode_fixstr, MPACK_TAG_SIZE_FIXSTR, (uint8_t)count);
-
- // str8 is only supported in v5 or later.
- } else if (count <= UINT8_MAX
- #if MPACK_COMPATIBILITY
- && writer->version >= mpack_version_v5
- #endif
- ) {
- MPACK_WRITE_ENCODED(mpack_encode_str8, MPACK_TAG_SIZE_STR8, (uint8_t)count);
-
- } else if (count <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_str16, MPACK_TAG_SIZE_STR16, (uint16_t)count);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_str32, MPACK_TAG_SIZE_STR32, (uint32_t)count);
- }
-}
-
-static void mpack_start_bin_notrack(mpack_writer_t* writer, uint32_t count) {
- #if MPACK_COMPATIBILITY
- // In the v4 spec, there was only the raw type for any kind of
- // variable-length data. In v4 mode, we support the bin functions,
- // but we produce an old-style raw.
- if (writer->version <= mpack_version_v4) {
- mpack_start_str_notrack(writer, count);
- return;
- }
- #endif
-
- if (count <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_bin8, MPACK_TAG_SIZE_BIN8, (uint8_t)count);
- } else if (count <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_bin16, MPACK_TAG_SIZE_BIN16, (uint16_t)count);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_bin32, MPACK_TAG_SIZE_BIN32, (uint32_t)count);
- }
-}
-
-void mpack_start_str(mpack_writer_t* writer, uint32_t count) {
- mpack_writer_track_element(writer);
- mpack_start_str_notrack(writer, count);
- mpack_writer_track_push(writer, mpack_type_str, count);
-}
-
-void mpack_start_bin(mpack_writer_t* writer, uint32_t count) {
- mpack_writer_track_element(writer);
- mpack_start_bin_notrack(writer, count);
- mpack_writer_track_push(writer, mpack_type_bin, count);
-}
-
-#if MPACK_EXTENSIONS
-void mpack_start_ext(mpack_writer_t* writer, int8_t exttype, uint32_t count) {
- #if MPACK_COMPATIBILITY
- if (writer->version <= mpack_version_v4) {
- mpack_break("Ext types require spec version v5 or later. This writer is in v%i mode.", (int)writer->version);
- mpack_writer_flag_error(writer, mpack_error_bug);
- return;
- }
- #endif
-
- mpack_writer_track_element(writer);
-
- if (count == 1) {
- MPACK_WRITE_ENCODED(mpack_encode_fixext1, MPACK_TAG_SIZE_FIXEXT1, exttype);
- } else if (count == 2) {
- MPACK_WRITE_ENCODED(mpack_encode_fixext2, MPACK_TAG_SIZE_FIXEXT2, exttype);
- } else if (count == 4) {
- MPACK_WRITE_ENCODED(mpack_encode_fixext4, MPACK_TAG_SIZE_FIXEXT4, exttype);
- } else if (count == 8) {
- MPACK_WRITE_ENCODED(mpack_encode_fixext8, MPACK_TAG_SIZE_FIXEXT8, exttype);
- } else if (count == 16) {
- MPACK_WRITE_ENCODED(mpack_encode_fixext16, MPACK_TAG_SIZE_FIXEXT16, exttype);
- } else if (count <= UINT8_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_ext8, MPACK_TAG_SIZE_EXT8, exttype, (uint8_t)count);
- } else if (count <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_ext16, MPACK_TAG_SIZE_EXT16, exttype, (uint16_t)count);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_ext32, MPACK_TAG_SIZE_EXT32, exttype, (uint32_t)count);
- }
-
- mpack_writer_track_push(writer, mpack_type_ext, count);
-}
-#endif
-
-
-
-/*
- * Compound helpers and other functions
- */
-
-void mpack_write_str(mpack_writer_t* writer, const char* data, uint32_t count) {
- mpack_assert(data != NULL, "data for string of length %i is NULL", (int)count);
-
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_writer_track_element(writer);
- mpack_start_str_notrack(writer, count);
- mpack_write_native(writer, data, count);
- #else
-
- mpack_writer_track_element(writer);
-
- if (count <= 31) {
- // The minimum buffer size when using a flush function is guaranteed to
- // fit the largest possible fixstr.
- size_t size = count + MPACK_TAG_SIZE_FIXSTR;
- if (MPACK_LIKELY(mpack_writer_buffer_left(writer) >= size) || mpack_writer_ensure(writer, size)) {
- char* MPACK_RESTRICT p = writer->current;
- mpack_encode_fixstr(p, (uint8_t)count);
- mpack_memcpy(p + MPACK_TAG_SIZE_FIXSTR, data, count);
- writer->current += count + MPACK_TAG_SIZE_FIXSTR;
- }
- return;
- }
-
- if (count <= UINT8_MAX
- #if MPACK_COMPATIBILITY
- && writer->version >= mpack_version_v5
- #endif
- ) {
- if (count + MPACK_TAG_SIZE_STR8 <= mpack_writer_buffer_left(writer)) {
- char* MPACK_RESTRICT p = writer->current;
- mpack_encode_str8(p, (uint8_t)count);
- mpack_memcpy(p + MPACK_TAG_SIZE_STR8, data, count);
- writer->current += count + MPACK_TAG_SIZE_STR8;
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_str8, MPACK_TAG_SIZE_STR8, (uint8_t)count);
- mpack_write_native(writer, data, count);
- }
- return;
- }
-
- // str16 and str32 are likely to be a significant fraction of the buffer
- // size, so we don't bother with a combined space check in order to
- // minimize code size.
- if (count <= UINT16_MAX) {
- MPACK_WRITE_ENCODED(mpack_encode_str16, MPACK_TAG_SIZE_STR16, (uint16_t)count);
- mpack_write_native(writer, data, count);
- } else {
- MPACK_WRITE_ENCODED(mpack_encode_str32, MPACK_TAG_SIZE_STR32, (uint32_t)count);
- mpack_write_native(writer, data, count);
- }
-
- #endif
-}
-
-void mpack_write_bin(mpack_writer_t* writer, const char* data, uint32_t count) {
- mpack_assert(data != NULL, "data pointer for bin of %i bytes is NULL", (int)count);
- mpack_start_bin(writer, count);
- mpack_write_bytes(writer, data, count);
- mpack_finish_bin(writer);
-}
-
-#if MPACK_EXTENSIONS
-void mpack_write_ext(mpack_writer_t* writer, int8_t exttype, const char* data, uint32_t count) {
- mpack_assert(data != NULL, "data pointer for ext of type %i and %i bytes is NULL", exttype, (int)count);
- mpack_start_ext(writer, exttype, count);
- mpack_write_bytes(writer, data, count);
- mpack_finish_ext(writer);
-}
-#endif
-
-void mpack_write_bytes(mpack_writer_t* writer, const char* data, size_t count) {
- mpack_assert(data != NULL, "data pointer for %i bytes is NULL", (int)count);
- mpack_writer_track_bytes(writer, count);
- mpack_write_native(writer, data, count);
-}
-
-void mpack_write_cstr(mpack_writer_t* writer, const char* cstr) {
- mpack_assert(cstr != NULL, "cstr pointer is NULL");
- size_t length = mpack_strlen(cstr);
- if (length > UINT32_MAX)
- mpack_writer_flag_error(writer, mpack_error_invalid);
- mpack_write_str(writer, cstr, (uint32_t)length);
-}
-
-void mpack_write_cstr_or_nil(mpack_writer_t* writer, const char* cstr) {
- if (cstr)
- mpack_write_cstr(writer, cstr);
- else
- mpack_write_nil(writer);
-}
-
-void mpack_write_utf8(mpack_writer_t* writer, const char* str, uint32_t length) {
- mpack_assert(str != NULL, "data for string of length %i is NULL", (int)length);
- if (!mpack_utf8_check(str, length)) {
- mpack_writer_flag_error(writer, mpack_error_invalid);
- return;
- }
- mpack_write_str(writer, str, length);
-}
-
-void mpack_write_utf8_cstr(mpack_writer_t* writer, const char* cstr) {
- mpack_assert(cstr != NULL, "cstr pointer is NULL");
- size_t length = mpack_strlen(cstr);
- if (length > UINT32_MAX) {
- mpack_writer_flag_error(writer, mpack_error_invalid);
- return;
- }
- mpack_write_utf8(writer, cstr, (uint32_t)length);
-}
-
-void mpack_write_utf8_cstr_or_nil(mpack_writer_t* writer, const char* cstr) {
- if (cstr)
- mpack_write_utf8_cstr(writer, cstr);
- else
- mpack_write_nil(writer);
-}
-
-#endif
-
-
-/* mpack/mpack-reader.c.c */
-
-#define MPACK_INTERNAL 1
-
-/* #include "mpack-reader.h" */
-
-#if MPACK_READER
-
-static void mpack_reader_skip_using_fill(mpack_reader_t* reader, size_t count);
-
-void mpack_reader_init(mpack_reader_t* reader, char* buffer, size_t size, size_t count) {
- mpack_assert(buffer != NULL, "buffer is NULL");
-
- mpack_memset(reader, 0, sizeof(*reader));
- reader->buffer = buffer;
- reader->size = size;
- reader->data = buffer;
- reader->end = buffer + count;
-
- #if MPACK_READ_TRACKING
- mpack_reader_flag_if_error(reader, mpack_track_init(&reader->track));
- #endif
-
- mpack_log("===========================\n");
- mpack_log("initializing reader with buffer size %i\n", (int)size);
-}
-
-void mpack_reader_init_error(mpack_reader_t* reader, mpack_error_t error) {
- mpack_memset(reader, 0, sizeof(*reader));
- reader->error = error;
-
- mpack_log("===========================\n");
- mpack_log("initializing reader error state %i\n", (int)error);
-}
-
-void mpack_reader_init_data(mpack_reader_t* reader, const char* data, size_t count) {
- mpack_assert(data != NULL, "data is NULL");
-
- mpack_memset(reader, 0, sizeof(*reader));
- reader->data = data;
- reader->end = data + count;
-
- #if MPACK_READ_TRACKING
- mpack_reader_flag_if_error(reader, mpack_track_init(&reader->track));
- #endif
-
- mpack_log("===========================\n");
- mpack_log("initializing reader with data size %i\n", (int)count);
-}
-
-void mpack_reader_set_fill(mpack_reader_t* reader, mpack_reader_fill_t fill) {
- MPACK_STATIC_ASSERT(MPACK_READER_MINIMUM_BUFFER_SIZE >= MPACK_MAXIMUM_TAG_SIZE,
- "minimum buffer size must fit any tag!");
-
- if (reader->size == 0) {
- mpack_break("cannot use fill function without a writeable buffer!");
- mpack_reader_flag_error(reader, mpack_error_bug);
- return;
- }
-
- if (reader->size < MPACK_READER_MINIMUM_BUFFER_SIZE) {
- mpack_break("buffer size is %i, but minimum buffer size for fill is %i",
- (int)reader->size, MPACK_READER_MINIMUM_BUFFER_SIZE);
- mpack_reader_flag_error(reader, mpack_error_bug);
- return;
- }
-
- reader->fill = fill;
-}
-
-void mpack_reader_set_skip(mpack_reader_t* reader, mpack_reader_skip_t skip) {
- mpack_assert(reader->size != 0, "cannot use skip function without a writeable buffer!");
- reader->skip = skip;
-}
-
-#if MPACK_STDIO
-static size_t mpack_file_reader_fill(mpack_reader_t* reader, char* buffer, size_t count) {
- if (feof((FILE *)reader->context)) {
- mpack_reader_flag_error(reader, mpack_error_eof);
- return 0;
- }
- return fread((void*)buffer, 1, count, (FILE*)reader->context);
-}
-
-static void mpack_file_reader_skip(mpack_reader_t* reader, size_t count) {
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- FILE* file = (FILE*)reader->context;
-
- // We call ftell() to test whether the stream is seekable
- // without causing a file error.
- if (ftell(file) >= 0) {
- mpack_log("seeking forward %i bytes\n", (int)count);
- if (fseek(file, (long int)count, SEEK_CUR) == 0)
- return;
- mpack_log("fseek() didn't return zero!\n");
- if (ferror(file)) {
- mpack_reader_flag_error(reader, mpack_error_io);
- return;
- }
- }
-
- // If the stream is not seekable, fall back to the fill function.
- mpack_reader_skip_using_fill(reader, count);
-}
-
-static void mpack_file_reader_teardown(mpack_reader_t* reader) {
- MPACK_FREE(reader->buffer);
- reader->buffer = NULL;
- reader->context = NULL;
- reader->size = 0;
- reader->fill = NULL;
- reader->skip = NULL;
- reader->teardown = NULL;
-}
-
-static void mpack_file_reader_teardown_close(mpack_reader_t* reader) {
- FILE* file = (FILE*)reader->context;
-
- if (file) {
- int ret = fclose(file);
- if (ret != 0)
- mpack_reader_flag_error(reader, mpack_error_io);
- }
-
- mpack_file_reader_teardown(reader);
-}
-
-void mpack_reader_init_stdfile(mpack_reader_t* reader, FILE* file, bool close_when_done) {
- mpack_assert(file != NULL, "file is NULL");
-
- size_t capacity = MPACK_BUFFER_SIZE;
- char* buffer = (char*)MPACK_MALLOC(capacity);
- if (buffer == NULL) {
- mpack_reader_init_error(reader, mpack_error_memory);
- if (close_when_done) {
- fclose(file);
- }
- return;
- }
-
- mpack_reader_init(reader, buffer, capacity, 0);
- mpack_reader_set_context(reader, file);
- mpack_reader_set_fill(reader, mpack_file_reader_fill);
- mpack_reader_set_skip(reader, mpack_file_reader_skip);
- mpack_reader_set_teardown(reader, close_when_done ?
- mpack_file_reader_teardown_close :
- mpack_file_reader_teardown);
-}
-
-void mpack_reader_init_filename(mpack_reader_t* reader, const char* filename) {
- mpack_assert(filename != NULL, "filename is NULL");
-
- FILE* file = fopen(filename, "rb");
- if (file == NULL) {
- mpack_reader_init_error(reader, mpack_error_io);
- return;
- }
-
- mpack_reader_init_stdfile(reader, file, true);
-}
-#endif
-
-mpack_error_t mpack_reader_destroy(mpack_reader_t* reader) {
-
- // clean up tracking, asserting if we're not already in an error state
- #if MPACK_READ_TRACKING
- mpack_reader_flag_if_error(reader, mpack_track_destroy(&reader->track, mpack_reader_error(reader) != mpack_ok));
- #endif
-
- if (reader->teardown)
- reader->teardown(reader);
- reader->teardown = NULL;
-
- return reader->error;
-}
-
-size_t mpack_reader_remaining(mpack_reader_t* reader, const char** data) {
- if (mpack_reader_error(reader) != mpack_ok)
- return 0;
-
- #if MPACK_READ_TRACKING
- if (mpack_reader_flag_if_error(reader, mpack_track_check_empty(&reader->track)) != mpack_ok)
- return 0;
- #endif
-
- if (data)
- *data = reader->data;
- return (size_t)(reader->end - reader->data);
-}
-
-void mpack_reader_flag_error(mpack_reader_t* reader, mpack_error_t error) {
- mpack_log("reader %p setting error %i: %s\n", reader, (int)error, mpack_error_to_string(error));
-
- if (reader->error == mpack_ok) {
- reader->error = error;
- reader->end = reader->data;
- if (reader->error_fn)
- reader->error_fn(reader, error);
- }
-}
-
-// Loops on the fill function, reading between the minimum and
-// maximum number of bytes and flagging an error if it fails.
-MPACK_NOINLINE static size_t mpack_fill_range(mpack_reader_t* reader, char* p, size_t min_bytes, size_t max_bytes) {
- mpack_assert(reader->fill != NULL, "mpack_fill_range() called with no fill function?");
- mpack_assert(min_bytes > 0, "cannot fill zero bytes!");
- mpack_assert(max_bytes >= min_bytes, "min_bytes %i cannot be larger than max_bytes %i!",
- (int)min_bytes, (int)max_bytes);
-
- size_t count = 0;
- while (count < min_bytes) {
- size_t read = reader->fill(reader, p + count, max_bytes - count);
-
- // Reader fill functions can flag an error or return 0 on failure. We
- // also guard against functions that -1 just in case.
- if (mpack_reader_error(reader) != mpack_ok)
- return 0;
- if (read == 0 || read == ((size_t)(-1))) {
- mpack_reader_flag_error(reader, mpack_error_io);
- return 0;
- }
-
- count += read;
- }
- return count;
-}
-
-MPACK_NOINLINE bool mpack_reader_ensure_straddle(mpack_reader_t* reader, size_t count) {
- mpack_assert(count != 0, "cannot ensure zero bytes!");
- mpack_assert(reader->error == mpack_ok, "reader cannot be in an error state!");
-
- mpack_assert(count > (size_t)(reader->end - reader->data),
- "straddling ensure requested for %i bytes, but there are %i bytes "
- "left in buffer. call mpack_reader_ensure() instead",
- (int)count, (int)(reader->end - reader->data));
-
- // we'll need a fill function to get more data. if there's no
- // fill function, the buffer should contain an entire MessagePack
- // object, so we raise mpack_error_invalid instead of mpack_error_io
- // on truncated data.
- if (reader->fill == NULL) {
- mpack_reader_flag_error(reader, mpack_error_invalid);
- return false;
- }
-
- // we need enough space in the buffer. if the buffer is not
- // big enough, we return mpack_error_too_big (since this is
- // for an in-place read larger than the buffer size.)
- if (count > reader->size) {
- mpack_reader_flag_error(reader, mpack_error_too_big);
- return false;
- }
-
- // move the existing data to the start of the buffer
- size_t left = (size_t)(reader->end - reader->data);
- mpack_memmove(reader->buffer, reader->data, left);
- reader->end -= reader->data - reader->buffer;
- reader->data = reader->buffer;
-
- // read at least the necessary number of bytes, accepting up to the
- // buffer size
- size_t read = mpack_fill_range(reader, reader->buffer + left,
- count - left, reader->size - left);
- if (mpack_reader_error(reader) != mpack_ok)
- return false;
- reader->end += read;
- return true;
-}
-
-// Reads count bytes into p. Used when there are not enough bytes
-// left in the buffer to satisfy a read.
-MPACK_NOINLINE void mpack_read_native_straddle(mpack_reader_t* reader, char* p, size_t count) {
- mpack_assert(count == 0 || p != NULL, "data pointer for %i bytes is NULL", (int)count);
-
- if (mpack_reader_error(reader) != mpack_ok) {
- mpack_memset(p, 0, count);
- return;
- }
-
- size_t left = (size_t)(reader->end - reader->data);
- mpack_log("big read for %i bytes into %p, %i left in buffer, buffer size %i\n",
- (int)count, p, (int)left, (int)reader->size);
-
- if (count <= left) {
- mpack_assert(0,
- "big read requested for %i bytes, but there are %i bytes "
- "left in buffer. call mpack_read_native() instead",
- (int)count, (int)left);
- mpack_reader_flag_error(reader, mpack_error_bug);
- mpack_memset(p, 0, count);
- return;
- }
-
- // we'll need a fill function to get more data. if there's no
- // fill function, the buffer should contain an entire MessagePack
- // object, so we raise mpack_error_invalid instead of mpack_error_io
- // on truncated data.
- if (reader->fill == NULL) {
- mpack_reader_flag_error(reader, mpack_error_invalid);
- mpack_memset(p, 0, count);
- return;
- }
-
- if (reader->size == 0) {
- // somewhat debatable what error should be returned here. when
- // initializing a reader with an in-memory buffer it's not
- // necessarily a bug if the data is blank; it might just have
- // been truncated to zero. for this reason we return the same
- // error as if the data was truncated.
- mpack_reader_flag_error(reader, mpack_error_io);
- mpack_memset(p, 0, count);
- return;
- }
-
- // flush what's left of the buffer
- if (left > 0) {
- mpack_log("flushing %i bytes remaining in buffer\n", (int)left);
- mpack_memcpy(p, reader->data, left);
- count -= left;
- p += left;
- reader->data += left;
- }
-
- // if the remaining data needed is some small fraction of the
- // buffer size, we'll try to fill the buffer as much as possible
- // and copy the needed data out.
- if (count <= reader->size / MPACK_READER_SMALL_FRACTION_DENOMINATOR) {
- size_t read = mpack_fill_range(reader, reader->buffer, count, reader->size);
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- mpack_memcpy(p, reader->buffer, count);
- reader->data = reader->buffer + count;
- reader->end = reader->buffer + read;
-
- // otherwise we read the remaining data directly into the target.
- } else {
- mpack_log("reading %i additional bytes\n", (int)count);
- mpack_fill_range(reader, p, count, count);
- }
-}
-
-MPACK_NOINLINE static void mpack_skip_bytes_straddle(mpack_reader_t* reader, size_t count) {
-
- // we'll need at least a fill function to skip more data. if there's
- // no fill function, the buffer should contain an entire MessagePack
- // object, so we raise mpack_error_invalid instead of mpack_error_io
- // on truncated data. (see mpack_read_native_straddle())
- if (reader->fill == NULL) {
- mpack_log("reader has no fill function!\n");
- mpack_reader_flag_error(reader, mpack_error_invalid);
- return;
- }
-
- // discard whatever's left in the buffer
- size_t left = (size_t)(reader->end - reader->data);
- mpack_log("discarding %i bytes still in buffer\n", (int)left);
- count -= left;
- reader->data = reader->end;
-
- // use the skip function if we've got one, and if we're trying
- // to skip a lot of data. if we only need to skip some tiny
- // fraction of the buffer size, it's probably better to just
- // fill the buffer and skip from it instead of trying to seek.
- if (reader->skip && count > reader->size / 16) {
- mpack_log("calling skip function for %i bytes\n", (int)count);
- reader->skip(reader, count);
- return;
- }
-
- mpack_reader_skip_using_fill(reader, count);
-}
-
-void mpack_skip_bytes(mpack_reader_t* reader, size_t count) {
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- mpack_log("skip requested for %i bytes\n", (int)count);
- mpack_reader_track_bytes(reader, count);
-
- // check if we have enough in the buffer already
- size_t left = (size_t)(reader->end - reader->data);
- if (left >= count) {
- mpack_log("skipping %i bytes still in buffer\n", (int)count);
- reader->data += count;
- return;
- }
-
- mpack_skip_bytes_straddle(reader, count);
-}
-
-MPACK_NOINLINE static void mpack_reader_skip_using_fill(mpack_reader_t* reader, size_t count) {
- mpack_assert(reader->fill != NULL, "missing fill function!");
- mpack_assert(reader->data == reader->end, "there are bytes left in the buffer!");
- mpack_assert(reader->error == mpack_ok, "should not have called this in an error state (%i)", reader->error);
- mpack_log("skip using fill for %i bytes\n", (int)count);
-
- // fill and discard multiples of the buffer size
- while (count > reader->size) {
- mpack_log("filling and discarding buffer of %i bytes\n", (int)reader->size);
- if (mpack_fill_range(reader, reader->buffer, reader->size, reader->size) < reader->size) {
- mpack_reader_flag_error(reader, mpack_error_io);
- return;
- }
- count -= reader->size;
- }
-
- // fill the buffer as much as possible
- reader->data = reader->buffer;
- size_t read = mpack_fill_range(reader, reader->buffer, count, reader->size);
- if (read < count) {
- mpack_reader_flag_error(reader, mpack_error_io);
- return;
- }
- reader->end = reader->data + read;
- mpack_log("filled %i bytes into buffer; discarding %i bytes\n", (int)read, (int)count);
- reader->data += count;
-}
-
-void mpack_read_bytes(mpack_reader_t* reader, char* p, size_t count) {
- mpack_assert(p != NULL, "destination for read of %i bytes is NULL", (int)count);
- mpack_reader_track_bytes(reader, count);
- mpack_read_native(reader, p, count);
-}
-
-void mpack_read_utf8(mpack_reader_t* reader, char* p, size_t byte_count) {
- mpack_assert(p != NULL, "destination for read of %i bytes is NULL", (int)byte_count);
- mpack_reader_track_str_bytes_all(reader, byte_count);
- mpack_read_native(reader, p, byte_count);
-
- if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check(p, byte_count))
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-static void mpack_read_cstr_unchecked(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) {
- mpack_assert(buf != NULL, "destination for read of %i bytes is NULL", (int)byte_count);
- mpack_assert(buffer_size >= 1, "buffer size is zero; you must have room for at least a null-terminator");
-
- if (mpack_reader_error(reader)) {
- buf[0] = 0;
- return;
- }
-
- if (byte_count > buffer_size - 1) {
- mpack_reader_flag_error(reader, mpack_error_too_big);
- buf[0] = 0;
- return;
- }
-
- mpack_reader_track_str_bytes_all(reader, byte_count);
- mpack_read_native(reader, buf, byte_count);
- buf[byte_count] = 0;
-}
-
-void mpack_read_cstr(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) {
- mpack_read_cstr_unchecked(reader, buf, buffer_size, byte_count);
-
- // check for null bytes
- if (mpack_reader_error(reader) == mpack_ok && !mpack_str_check_no_null(buf, byte_count)) {
- buf[0] = 0;
- mpack_reader_flag_error(reader, mpack_error_type);
- }
-}
-
-void mpack_read_utf8_cstr(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) {
- mpack_read_cstr_unchecked(reader, buf, buffer_size, byte_count);
-
- // check encoding
- if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check_no_null(buf, byte_count)) {
- buf[0] = 0;
- mpack_reader_flag_error(reader, mpack_error_type);
- }
-}
-
-#ifdef MPACK_MALLOC
-// Reads native bytes with error callback disabled. This allows MPack reader functions
-// to hold an allocated buffer and read native data into it without leaking it in
-// case of a non-local jump (longjmp, throw) out of an error handler.
-static void mpack_read_native_noerrorfn(mpack_reader_t* reader, char* p, size_t count) {
- mpack_assert(reader->error == mpack_ok, "cannot call if an error is already flagged!");
- mpack_reader_error_t error_fn = reader->error_fn;
- reader->error_fn = NULL;
- mpack_read_native(reader, p, count);
- reader->error_fn = error_fn;
-}
-
-char* mpack_read_bytes_alloc_impl(mpack_reader_t* reader, size_t count, bool null_terminated) {
-
- // track the bytes first in case it jumps
- mpack_reader_track_bytes(reader, count);
- if (mpack_reader_error(reader) != mpack_ok)
- return NULL;
-
- // cannot allocate zero bytes. this is not an error.
- if (count == 0 && null_terminated == false)
- return NULL;
-
- // allocate data
- char* data = (char*)MPACK_MALLOC(count + (null_terminated ? 1 : 0)); // TODO: can this overflow?
- if (data == NULL) {
- mpack_reader_flag_error(reader, mpack_error_memory);
- return NULL;
- }
-
- // read with error callback disabled so we don't leak our buffer
- mpack_read_native_noerrorfn(reader, data, count);
-
- // report flagged errors
- if (mpack_reader_error(reader) != mpack_ok) {
- MPACK_FREE(data);
- if (reader->error_fn)
- reader->error_fn(reader, mpack_reader_error(reader));
- return NULL;
- }
-
- if (null_terminated)
- data[count] = '\0';
- return data;
-}
-#endif
-
-// read inplace without tracking (since there are different
-// tracking modes for different inplace readers)
-static const char* mpack_read_bytes_inplace_notrack(mpack_reader_t* reader, size_t count) {
- if (mpack_reader_error(reader) != mpack_ok)
- return NULL;
-
- // if we have enough bytes already in the buffer, we can return it directly.
- if ((size_t)(reader->end - reader->data) >= count) {
- const char* bytes = reader->data;
- reader->data += count;
- return bytes;
- }
-
- if (!mpack_reader_ensure(reader, count))
- return NULL;
-
- const char* bytes = reader->data;
- reader->data += count;
- return bytes;
-}
-
-const char* mpack_read_bytes_inplace(mpack_reader_t* reader, size_t count) {
- mpack_reader_track_bytes(reader, count);
- return mpack_read_bytes_inplace_notrack(reader, count);
-}
-
-const char* mpack_read_utf8_inplace(mpack_reader_t* reader, size_t count) {
- mpack_reader_track_str_bytes_all(reader, count);
- const char* str = mpack_read_bytes_inplace_notrack(reader, count);
-
- if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check(str, count)) {
- mpack_reader_flag_error(reader, mpack_error_type);
- return NULL;
- }
-
- return str;
-}
-
-static size_t mpack_parse_tag(mpack_reader_t* reader, mpack_tag_t* tag) {
- mpack_assert(reader->error == mpack_ok, "reader cannot be in an error state!");
-
- if (!mpack_reader_ensure(reader, 1))
- return 0;
- uint8_t type = mpack_load_u8(reader->data);
-
- // unfortunately, by far the fastest way to parse a tag is to switch
- // on the first byte, and to explicitly list every possible byte. so for
- // infix types, the list of cases is quite large.
- //
- // in size-optimized builds, we switch on the top four bits first to
- // handle most infix types with a smaller jump table to save space.
-
- #if MPACK_OPTIMIZE_FOR_SIZE
- switch (type >> 4) {
-
- // positive fixnum
- case 0x0: case 0x1: case 0x2: case 0x3:
- case 0x4: case 0x5: case 0x6: case 0x7:
- *tag = mpack_tag_make_uint(type);
- return 1;
-
- // negative fixnum
- case 0xe: case 0xf:
- *tag = mpack_tag_make_int((int8_t)type);
- return 1;
-
- // fixmap
- case 0x8:
- *tag = mpack_tag_make_map(type & ~0xf0u);
- return 1;
-
- // fixarray
- case 0x9:
- *tag = mpack_tag_make_array(type & ~0xf0u);
- return 1;
-
- // fixstr
- case 0xa: case 0xb:
- *tag = mpack_tag_make_str(type & ~0xe0u);
- return 1;
-
- // not one of the common infix types
- default:
- break;
-
- }
- #endif
-
- // handle individual type tags
- switch (type) {
-
- #if !MPACK_OPTIMIZE_FOR_SIZE
- // positive fixnum
- case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
- case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
- case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
- case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
- case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
- case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
- case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
- case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
- case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
- case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
- case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
- case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
- case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
- *tag = mpack_tag_make_uint(type);
- return 1;
-
- // negative fixnum
- case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
- case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
- case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
- case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
- *tag = mpack_tag_make_int((int8_t)type);
- return 1;
-
- // fixmap
- case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
- case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
- *tag = mpack_tag_make_map(type & ~0xf0u);
- return 1;
-
- // fixarray
- case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
- case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
- *tag = mpack_tag_make_array(type & ~0xf0u);
- return 1;
-
- // fixstr
- case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
- case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
- case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
- case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
- *tag = mpack_tag_make_str(type & ~0xe0u);
- return 1;
- #endif
-
- // nil
- case 0xc0:
- *tag = mpack_tag_make_nil();
- return 1;
-
- // bool
- case 0xc2: case 0xc3:
- *tag = mpack_tag_make_bool((bool)(type & 1));
- return 1;
-
- // bin8
- case 0xc4:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_BIN8))
- return 0;
- *tag = mpack_tag_make_bin(mpack_load_u8(reader->data + 1));
- return MPACK_TAG_SIZE_BIN8;
-
- // bin16
- case 0xc5:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_BIN16))
- return 0;
- *tag = mpack_tag_make_bin(mpack_load_u16(reader->data + 1));
- return MPACK_TAG_SIZE_BIN16;
-
- // bin32
- case 0xc6:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_BIN32))
- return 0;
- *tag = mpack_tag_make_bin(mpack_load_u32(reader->data + 1));
- return MPACK_TAG_SIZE_BIN32;
-
- #if MPACK_EXTENSIONS
- // ext8
- case 0xc7:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_EXT8))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 2), mpack_load_u8(reader->data + 1));
- return MPACK_TAG_SIZE_EXT8;
-
- // ext16
- case 0xc8:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_EXT16))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 3), mpack_load_u16(reader->data + 1));
- return MPACK_TAG_SIZE_EXT16;
-
- // ext32
- case 0xc9:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_EXT32))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 5), mpack_load_u32(reader->data + 1));
- return MPACK_TAG_SIZE_EXT32;
- #endif
-
- // float
- case 0xca:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FLOAT))
- return 0;
- *tag = mpack_tag_make_float(mpack_load_float(reader->data + 1));
- return MPACK_TAG_SIZE_FLOAT;
-
- // double
- case 0xcb:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_DOUBLE))
- return 0;
- *tag = mpack_tag_make_double(mpack_load_double(reader->data + 1));
- return MPACK_TAG_SIZE_DOUBLE;
-
- // uint8
- case 0xcc:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U8))
- return 0;
- *tag = mpack_tag_make_uint(mpack_load_u8(reader->data + 1));
- return MPACK_TAG_SIZE_U8;
-
- // uint16
- case 0xcd:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U16))
- return 0;
- *tag = mpack_tag_make_uint(mpack_load_u16(reader->data + 1));
- return MPACK_TAG_SIZE_U16;
-
- // uint32
- case 0xce:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U32))
- return 0;
- *tag = mpack_tag_make_uint(mpack_load_u32(reader->data + 1));
- return MPACK_TAG_SIZE_U32;
-
- // uint64
- case 0xcf:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U64))
- return 0;
- *tag = mpack_tag_make_uint(mpack_load_u64(reader->data + 1));
- return MPACK_TAG_SIZE_U64;
-
- // int8
- case 0xd0:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I8))
- return 0;
- *tag = mpack_tag_make_int(mpack_load_i8(reader->data + 1));
- return MPACK_TAG_SIZE_I8;
-
- // int16
- case 0xd1:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I16))
- return 0;
- *tag = mpack_tag_make_int(mpack_load_i16(reader->data + 1));
- return MPACK_TAG_SIZE_I16;
-
- // int32
- case 0xd2:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I32))
- return 0;
- *tag = mpack_tag_make_int(mpack_load_i32(reader->data + 1));
- return MPACK_TAG_SIZE_I32;
-
- // int64
- case 0xd3:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I64))
- return 0;
- *tag = mpack_tag_make_int(mpack_load_i64(reader->data + 1));
- return MPACK_TAG_SIZE_I64;
-
- #if MPACK_EXTENSIONS
- // fixext1
- case 0xd4:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT1))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 1);
- return MPACK_TAG_SIZE_FIXEXT1;
-
- // fixext2
- case 0xd5:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT2))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 2);
- return MPACK_TAG_SIZE_FIXEXT2;
-
- // fixext4
- case 0xd6:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT4))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 4);
- return 2;
-
- // fixext8
- case 0xd7:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT8))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 8);
- return MPACK_TAG_SIZE_FIXEXT8;
-
- // fixext16
- case 0xd8:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT16))
- return 0;
- *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 16);
- return MPACK_TAG_SIZE_FIXEXT16;
- #endif
-
- // str8
- case 0xd9:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_STR8))
- return 0;
- *tag = mpack_tag_make_str(mpack_load_u8(reader->data + 1));
- return MPACK_TAG_SIZE_STR8;
-
- // str16
- case 0xda:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_STR16))
- return 0;
- *tag = mpack_tag_make_str(mpack_load_u16(reader->data + 1));
- return MPACK_TAG_SIZE_STR16;
-
- // str32
- case 0xdb:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_STR32))
- return 0;
- *tag = mpack_tag_make_str(mpack_load_u32(reader->data + 1));
- return MPACK_TAG_SIZE_STR32;
-
- // array16
- case 0xdc:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_ARRAY16))
- return 0;
- *tag = mpack_tag_make_array(mpack_load_u16(reader->data + 1));
- return MPACK_TAG_SIZE_ARRAY16;
-
- // array32
- case 0xdd:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_ARRAY32))
- return 0;
- *tag = mpack_tag_make_array(mpack_load_u32(reader->data + 1));
- return MPACK_TAG_SIZE_ARRAY32;
-
- // map16
- case 0xde:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_MAP16))
- return 0;
- *tag = mpack_tag_make_map(mpack_load_u16(reader->data + 1));
- return MPACK_TAG_SIZE_MAP16;
-
- // map32
- case 0xdf:
- if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_MAP32))
- return 0;
- *tag = mpack_tag_make_map(mpack_load_u32(reader->data + 1));
- return MPACK_TAG_SIZE_MAP32;
-
- // reserved
- case 0xc1:
- mpack_reader_flag_error(reader, mpack_error_invalid);
- return 0;
-
- #if !MPACK_EXTENSIONS
- // ext
- case 0xc7: // fallthrough
- case 0xc8: // fallthrough
- case 0xc9: // fallthrough
- // fixext
- case 0xd4: // fallthrough
- case 0xd5: // fallthrough
- case 0xd6: // fallthrough
- case 0xd7: // fallthrough
- case 0xd8:
- mpack_reader_flag_error(reader, mpack_error_unsupported);
- return 0;
- #endif
-
- #if MPACK_OPTIMIZE_FOR_SIZE
- // any other bytes should have been handled by the infix switch
- default:
- break;
- #endif
- }
-
- mpack_assert(0, "unreachable");
- return 0;
-}
-
-mpack_tag_t mpack_read_tag(mpack_reader_t* reader) {
- mpack_log("reading tag\n");
-
- // make sure we can read a tag
- if (mpack_reader_error(reader) != mpack_ok)
- return mpack_tag_nil();
- if (mpack_reader_track_element(reader) != mpack_ok)
- return mpack_tag_nil();
-
- mpack_tag_t tag = MPACK_TAG_ZERO;
- size_t count = mpack_parse_tag(reader, &tag);
- if (count == 0)
- return mpack_tag_nil();
-
- #if MPACK_READ_TRACKING
- mpack_error_t track_error = mpack_ok;
-
- switch (tag.type) {
- case mpack_type_map:
- case mpack_type_array:
- track_error = mpack_track_push(&reader->track, tag.type, tag.v.n);
- break;
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- #endif
- case mpack_type_str:
- case mpack_type_bin:
- track_error = mpack_track_push(&reader->track, tag.type, tag.v.l);
- break;
- default:
- break;
- }
-
- if (track_error != mpack_ok) {
- mpack_reader_flag_error(reader, track_error);
- return mpack_tag_nil();
- }
- #endif
-
- reader->data += count;
- return tag;
-}
-
-mpack_tag_t mpack_peek_tag(mpack_reader_t* reader) {
- mpack_log("peeking tag\n");
-
- // make sure we can peek a tag
- if (mpack_reader_error(reader) != mpack_ok)
- return mpack_tag_nil();
- if (mpack_reader_track_peek_element(reader) != mpack_ok)
- return mpack_tag_nil();
-
- mpack_tag_t tag = MPACK_TAG_ZERO;
- if (mpack_parse_tag(reader, &tag) == 0)
- return mpack_tag_nil();
- return tag;
-}
-
-void mpack_discard(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (mpack_reader_error(reader))
- return;
- switch (var.type) {
- case mpack_type_str:
- mpack_skip_bytes(reader, var.v.l);
- mpack_done_str(reader);
- break;
- case mpack_type_bin:
- mpack_skip_bytes(reader, var.v.l);
- mpack_done_bin(reader);
- break;
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- mpack_skip_bytes(reader, var.v.l);
- mpack_done_ext(reader);
- break;
- #endif
- case mpack_type_array: {
- for (; var.v.n > 0; --var.v.n) {
- mpack_discard(reader);
- if (mpack_reader_error(reader))
- break;
- }
- mpack_done_array(reader);
- break;
- }
- case mpack_type_map: {
- for (; var.v.n > 0; --var.v.n) {
- mpack_discard(reader);
- mpack_discard(reader);
- if (mpack_reader_error(reader))
- break;
- }
- mpack_done_map(reader);
- break;
- }
- default:
- break;
- }
-}
-
-#if MPACK_EXTENSIONS
-mpack_timestamp_t mpack_read_timestamp(mpack_reader_t* reader, size_t size) {
- mpack_timestamp_t timestamp = {0, 0};
-
- if (size != 4 && size != 8 && size != 12) {
- mpack_reader_flag_error(reader, mpack_error_invalid);
- return timestamp;
- }
-
- char buf[12];
- mpack_read_bytes(reader, buf, size);
- mpack_done_ext(reader);
- if (mpack_reader_error(reader) != mpack_ok)
- return timestamp;
-
- switch (size) {
- case 4:
- timestamp.seconds = (int64_t)(uint64_t)mpack_load_u32(buf);
- break;
-
- case 8: {
- uint64_t packed = mpack_load_u64(buf);
- timestamp.seconds = (int64_t)(packed & ((UINT64_C(1) << 34) - 1));
- timestamp.nanoseconds = (uint32_t)(packed >> 34);
- break;
- }
-
- case 12:
- timestamp.nanoseconds = mpack_load_u32(buf);
- timestamp.seconds = mpack_load_i64(buf + 4);
- break;
-
- default:
- mpack_assert(false, "unreachable");
- break;
- }
-
- if (timestamp.nanoseconds > MPACK_TIMESTAMP_NANOSECONDS_MAX) {
- mpack_reader_flag_error(reader, mpack_error_invalid);
- mpack_timestamp_t zero = {0, 0};
- return zero;
- }
-
- return timestamp;
-}
-#endif
-
-#if MPACK_READ_TRACKING
-void mpack_done_type(mpack_reader_t* reader, mpack_type_t type) {
- if (mpack_reader_error(reader) == mpack_ok)
- mpack_reader_flag_if_error(reader, mpack_track_pop(&reader->track, type));
-}
-#endif
-
-#if MPACK_DEBUG && MPACK_STDIO
-static size_t mpack_print_read_prefix(mpack_reader_t* reader, size_t length, char* buffer, size_t buffer_size) {
- if (length == 0)
- return 0;
-
- size_t read = (length < buffer_size) ? length : buffer_size;
- mpack_read_bytes(reader, buffer, read);
- if (mpack_reader_error(reader) != mpack_ok)
- return 0;
-
- mpack_skip_bytes(reader, length - read);
- return read;
-}
-
-static void mpack_print_element(mpack_reader_t* reader, mpack_print_t* print, size_t depth) {
- mpack_tag_t val = mpack_read_tag(reader);
- if (mpack_reader_error(reader) != mpack_ok)
- return;
-
- // We read some bytes from bin and ext so we can print its prefix in hex.
- char buffer[MPACK_PRINT_BYTE_COUNT];
- size_t count = 0;
-
- switch (val.type) {
- case mpack_type_str:
- mpack_print_append_cstr(print, "\"");
- for (size_t i = 0; i < val.v.l; ++i) {
- char c;
- mpack_read_bytes(reader, &c, 1);
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- switch (c) {
- case '\n': mpack_print_append_cstr(print, "\\n"); break;
- case '\\': mpack_print_append_cstr(print, "\\\\"); break;
- case '"': mpack_print_append_cstr(print, "\\\""); break;
- default: mpack_print_append(print, &c, 1); break;
- }
- }
- mpack_print_append_cstr(print, "\"");
- mpack_done_str(reader);
- return;
-
- case mpack_type_array:
- mpack_print_append_cstr(print, "[\n");
- for (size_t i = 0; i < val.v.n; ++i) {
- for (size_t j = 0; j < depth + 1; ++j)
- mpack_print_append_cstr(print, " ");
- mpack_print_element(reader, print, depth + 1);
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- if (i != val.v.n - 1)
- mpack_print_append_cstr(print, ",");
- mpack_print_append_cstr(print, "\n");
- }
- for (size_t i = 0; i < depth; ++i)
- mpack_print_append_cstr(print, " ");
- mpack_print_append_cstr(print, "]");
- mpack_done_array(reader);
- return;
-
- case mpack_type_map:
- mpack_print_append_cstr(print, "{\n");
- for (size_t i = 0; i < val.v.n; ++i) {
- for (size_t j = 0; j < depth + 1; ++j)
- mpack_print_append_cstr(print, " ");
- mpack_print_element(reader, print, depth + 1);
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- mpack_print_append_cstr(print, ": ");
- mpack_print_element(reader, print, depth + 1);
- if (mpack_reader_error(reader) != mpack_ok)
- return;
- if (i != val.v.n - 1)
- mpack_print_append_cstr(print, ",");
- mpack_print_append_cstr(print, "\n");
- }
- for (size_t i = 0; i < depth; ++i)
- mpack_print_append_cstr(print, " ");
- mpack_print_append_cstr(print, "}");
- mpack_done_map(reader);
- return;
-
- // The above cases return so as not to print a pseudo-json value. The
- // below cases break and print pseudo-json.
-
- case mpack_type_bin:
- count = mpack_print_read_prefix(reader, mpack_tag_bin_length(&val), buffer, sizeof(buffer));
- mpack_done_bin(reader);
- break;
-
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- count = mpack_print_read_prefix(reader, mpack_tag_ext_length(&val), buffer, sizeof(buffer));
- mpack_done_ext(reader);
- break;
- #endif
-
- default:
- break;
- }
-
- char buf[256];
- mpack_tag_debug_pseudo_json(val, buf, sizeof(buf), buffer, count);
- mpack_print_append_cstr(print, buf);
-}
-
-static void mpack_print_and_destroy(mpack_reader_t* reader, mpack_print_t* print, size_t depth) {
- for (size_t i = 0; i < depth; ++i)
- mpack_print_append_cstr(print, " ");
- mpack_print_element(reader, print, depth);
-
- size_t remaining = mpack_reader_remaining(reader, NULL);
-
- char buf[256];
- if (mpack_reader_destroy(reader) != mpack_ok) {
- mpack_snprintf(buf, sizeof(buf), "\n<mpack parsing error %s>", mpack_error_to_string(mpack_reader_error(reader)));
- buf[sizeof(buf) - 1] = '\0';
- mpack_print_append_cstr(print, buf);
- } else if (remaining > 0) {
- mpack_snprintf(buf, sizeof(buf), "\n<%i extra bytes at end of message>", (int)remaining);
- buf[sizeof(buf) - 1] = '\0';
- mpack_print_append_cstr(print, buf);
- }
-}
-
-static void mpack_print_data(const char* data, size_t len, mpack_print_t* print, size_t depth) {
- mpack_reader_t reader;
- mpack_reader_init_data(&reader, data, len);
- mpack_print_and_destroy(&reader, print, depth);
-}
-
-void mpack_print_data_to_buffer(const char* data, size_t data_size, char* buffer, size_t buffer_size) {
- if (buffer_size == 0) {
- mpack_assert(false, "buffer size is zero!");
- return;
- }
-
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = buffer_size;
- mpack_print_data(data, data_size, &print, 0);
- mpack_print_append(&print, "", 1); // null-terminator
- mpack_print_flush(&print);
-
- // we always make sure there's a null-terminator at the end of the buffer
- // in case we ran out of space.
- print.buffer[print.size - 1] = '\0';
-}
-
-void mpack_print_data_to_callback(const char* data, size_t size, mpack_print_callback_t callback, void* context) {
- char buffer[1024];
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = sizeof(buffer);
- print.callback = callback;
- print.context = context;
- mpack_print_data(data, size, &print, 0);
- mpack_print_flush(&print);
-}
-
-void mpack_print_data_to_file(const char* data, size_t len, FILE* file) {
- mpack_assert(data != NULL, "data is NULL");
- mpack_assert(file != NULL, "file is NULL");
-
- char buffer[1024];
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = sizeof(buffer);
- print.callback = &mpack_print_file_callback;
- print.context = file;
-
- mpack_print_data(data, len, &print, 2);
- mpack_print_append_cstr(&print, "\n");
- mpack_print_flush(&print);
-}
-
-void mpack_print_stdfile_to_callback(FILE* file, mpack_print_callback_t callback, void* context) {
- char buffer[1024];
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = sizeof(buffer);
- print.callback = callback;
- print.context = context;
-
- mpack_reader_t reader;
- mpack_reader_init_stdfile(&reader, file, false);
- mpack_print_and_destroy(&reader, &print, 0);
- mpack_print_flush(&print);
-}
-#endif
-
-#endif
-
-/* mpack/mpack-expect.c.c */
-
-#define MPACK_INTERNAL 1
-
-/* #include "mpack-expect.h" */
-
-#if MPACK_EXPECT
-
-
-// Helpers
-
-MPACK_STATIC_INLINE uint8_t mpack_expect_native_u8(mpack_reader_t* reader) {
- if (mpack_reader_error(reader) != mpack_ok)
- return 0;
- uint8_t type;
- if (!mpack_reader_ensure(reader, sizeof(type)))
- return 0;
- type = mpack_load_u8(reader->data);
- reader->data += sizeof(type);
- return type;
-}
-
-#if !MPACK_OPTIMIZE_FOR_SIZE
-MPACK_STATIC_INLINE uint16_t mpack_expect_native_u16(mpack_reader_t* reader) {
- if (mpack_reader_error(reader) != mpack_ok)
- return 0;
- uint16_t type;
- if (!mpack_reader_ensure(reader, sizeof(type)))
- return 0;
- type = mpack_load_u16(reader->data);
- reader->data += sizeof(type);
- return type;
-}
-
-MPACK_STATIC_INLINE uint32_t mpack_expect_native_u32(mpack_reader_t* reader) {
- if (mpack_reader_error(reader) != mpack_ok)
- return 0;
- uint32_t type;
- if (!mpack_reader_ensure(reader, sizeof(type)))
- return 0;
- type = mpack_load_u32(reader->data);
- reader->data += sizeof(type);
- return type;
-}
-#endif
-
-MPACK_STATIC_INLINE uint8_t mpack_expect_type_byte(mpack_reader_t* reader) {
- mpack_reader_track_element(reader);
- return mpack_expect_native_u8(reader);
-}
-
-
-// Basic Number Functions
-
-uint8_t mpack_expect_u8(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= UINT8_MAX)
- return (uint8_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= 0 && var.v.i <= UINT8_MAX)
- return (uint8_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-uint16_t mpack_expect_u16(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= UINT16_MAX)
- return (uint16_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= 0 && var.v.i <= UINT16_MAX)
- return (uint16_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-uint32_t mpack_expect_u32(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= UINT32_MAX)
- return (uint32_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= 0 && var.v.i <= UINT32_MAX)
- return (uint32_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-uint64_t mpack_expect_u64(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- return var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= 0)
- return (uint64_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-int8_t mpack_expect_i8(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= INT8_MAX)
- return (int8_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= INT8_MIN && var.v.i <= INT8_MAX)
- return (int8_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-int16_t mpack_expect_i16(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= INT16_MAX)
- return (int16_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= INT16_MIN && var.v.i <= INT16_MAX)
- return (int16_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-int32_t mpack_expect_i32(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= INT32_MAX)
- return (int32_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- if (var.v.i >= INT32_MIN && var.v.i <= INT32_MAX)
- return (int32_t)var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-int64_t mpack_expect_i64(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint) {
- if (var.v.u <= INT64_MAX)
- return (int64_t)var.v.u;
- } else if (var.type == mpack_type_int) {
- return var.v.i;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-float mpack_expect_float(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint)
- return (float)var.v.u;
- else if (var.type == mpack_type_int)
- return (float)var.v.i;
- else if (var.type == mpack_type_float)
- return var.v.f;
- else if (var.type == mpack_type_double)
- return (float)var.v.d;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0.0f;
-}
-
-double mpack_expect_double(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_uint)
- return (double)var.v.u;
- else if (var.type == mpack_type_int)
- return (double)var.v.i;
- else if (var.type == mpack_type_float)
- return (double)var.v.f;
- else if (var.type == mpack_type_double)
- return var.v.d;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0.0;
-}
-
-float mpack_expect_float_strict(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_float)
- return var.v.f;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0.0f;
-}
-
-double mpack_expect_double_strict(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_float)
- return (double)var.v.f;
- else if (var.type == mpack_type_double)
- return var.v.d;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0.0;
-}
-
-
-// Ranged Number Functions
-//
-// All ranged functions are identical other than the type, so we
-// define their content with a macro. The prototypes are still written
-// out in full to support ctags/IDE tools.
-
-#define MPACK_EXPECT_RANGE_IMPL(name, type_t) \
- \
- /* make sure the range is sensible */ \
- mpack_assert(min_value <= max_value, \
- "min_value %i must be less than or equal to max_value %i", \
- min_value, max_value); \
- \
- /* read the value */ \
- type_t val = mpack_expect_##name(reader); \
- if (mpack_reader_error(reader) != mpack_ok) \
- return min_value; \
- \
- /* make sure it fits */ \
- if (val < min_value || val > max_value) { \
- mpack_reader_flag_error(reader, mpack_error_type); \
- return min_value; \
- } \
- \
- return val;
-
-uint8_t mpack_expect_u8_range(mpack_reader_t* reader, uint8_t min_value, uint8_t max_value) {MPACK_EXPECT_RANGE_IMPL(u8, uint8_t)}
-uint16_t mpack_expect_u16_range(mpack_reader_t* reader, uint16_t min_value, uint16_t max_value) {MPACK_EXPECT_RANGE_IMPL(u16, uint16_t)}
-uint32_t mpack_expect_u32_range(mpack_reader_t* reader, uint32_t min_value, uint32_t max_value) {MPACK_EXPECT_RANGE_IMPL(u32, uint32_t)}
-uint64_t mpack_expect_u64_range(mpack_reader_t* reader, uint64_t min_value, uint64_t max_value) {MPACK_EXPECT_RANGE_IMPL(u64, uint64_t)}
-
-int8_t mpack_expect_i8_range(mpack_reader_t* reader, int8_t min_value, int8_t max_value) {MPACK_EXPECT_RANGE_IMPL(i8, int8_t)}
-int16_t mpack_expect_i16_range(mpack_reader_t* reader, int16_t min_value, int16_t max_value) {MPACK_EXPECT_RANGE_IMPL(i16, int16_t)}
-int32_t mpack_expect_i32_range(mpack_reader_t* reader, int32_t min_value, int32_t max_value) {MPACK_EXPECT_RANGE_IMPL(i32, int32_t)}
-int64_t mpack_expect_i64_range(mpack_reader_t* reader, int64_t min_value, int64_t max_value) {MPACK_EXPECT_RANGE_IMPL(i64, int64_t)}
-
-float mpack_expect_float_range(mpack_reader_t* reader, float min_value, float max_value) {MPACK_EXPECT_RANGE_IMPL(float, float)}
-double mpack_expect_double_range(mpack_reader_t* reader, double min_value, double max_value) {MPACK_EXPECT_RANGE_IMPL(double, double)}
-
-uint32_t mpack_expect_map_range(mpack_reader_t* reader, uint32_t min_value, uint32_t max_value) {MPACK_EXPECT_RANGE_IMPL(map, uint32_t)}
-uint32_t mpack_expect_array_range(mpack_reader_t* reader, uint32_t min_value, uint32_t max_value) {MPACK_EXPECT_RANGE_IMPL(array, uint32_t)}
-
-
-// Matching Number Functions
-
-void mpack_expect_uint_match(mpack_reader_t* reader, uint64_t value) {
- if (mpack_expect_u64(reader) != value)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-void mpack_expect_int_match(mpack_reader_t* reader, int64_t value) {
- if (mpack_expect_i64(reader) != value)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-
-// Other Basic Types
-
-void mpack_expect_nil(mpack_reader_t* reader) {
- if (mpack_expect_type_byte(reader) != 0xc0)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-bool mpack_expect_bool(mpack_reader_t* reader) {
- uint8_t type = mpack_expect_type_byte(reader);
- if ((type & ~1) != 0xc2)
- mpack_reader_flag_error(reader, mpack_error_type);
- return (bool)(type & 1);
-}
-
-void mpack_expect_true(mpack_reader_t* reader) {
- if (mpack_expect_bool(reader) != true)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-void mpack_expect_false(mpack_reader_t* reader) {
- if (mpack_expect_bool(reader) != false)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-#if MPACK_EXTENSIONS
-mpack_timestamp_t mpack_expect_timestamp(mpack_reader_t* reader) {
- mpack_timestamp_t zero = {0, 0};
-
- mpack_tag_t tag = mpack_read_tag(reader);
- if (tag.type != mpack_type_ext) {
- mpack_reader_flag_error(reader, mpack_error_type);
- return zero;
- }
- if (mpack_tag_ext_exttype(&tag) != MPACK_EXTTYPE_TIMESTAMP) {
- mpack_reader_flag_error(reader, mpack_error_type);
- return zero;
- }
-
- return mpack_read_timestamp(reader, mpack_tag_ext_length(&tag));
-}
-
-int64_t mpack_expect_timestamp_truncate(mpack_reader_t* reader) {
- return mpack_expect_timestamp(reader).seconds;
-}
-#endif
-
-
-// Compound Types
-
-uint32_t mpack_expect_map(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_map)
- return var.v.n;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-void mpack_expect_map_match(mpack_reader_t* reader, uint32_t count) {
- if (mpack_expect_map(reader) != count)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-bool mpack_expect_map_or_nil(mpack_reader_t* reader, uint32_t* count) {
- mpack_assert(count != NULL, "count cannot be NULL");
-
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_nil) {
- *count = 0;
- return false;
- }
- if (var.type == mpack_type_map) {
- *count = var.v.n;
- return true;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- *count = 0;
- return false;
-}
-
-bool mpack_expect_map_max_or_nil(mpack_reader_t* reader, uint32_t max_count, uint32_t* count) {
- mpack_assert(count != NULL, "count cannot be NULL");
-
- bool has_map = mpack_expect_map_or_nil(reader, count);
- if (has_map && *count > max_count) {
- *count = 0;
- mpack_reader_flag_error(reader, mpack_error_type);
- return false;
- }
- return has_map;
-}
-
-uint32_t mpack_expect_array(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_array)
- return var.v.n;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-void mpack_expect_array_match(mpack_reader_t* reader, uint32_t count) {
- if (mpack_expect_array(reader) != count)
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-bool mpack_expect_array_or_nil(mpack_reader_t* reader, uint32_t* count) {
- mpack_assert(count != NULL, "count cannot be NULL");
-
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_nil) {
- *count = 0;
- return false;
- }
- if (var.type == mpack_type_array) {
- *count = var.v.n;
- return true;
- }
- mpack_reader_flag_error(reader, mpack_error_type);
- *count = 0;
- return false;
-}
-
-bool mpack_expect_array_max_or_nil(mpack_reader_t* reader, uint32_t max_count, uint32_t* count) {
- mpack_assert(count != NULL, "count cannot be NULL");
-
- bool has_array = mpack_expect_array_or_nil(reader, count);
- if (has_array && *count > max_count) {
- *count = 0;
- mpack_reader_flag_error(reader, mpack_error_type);
- return false;
- }
- return has_array;
-}
-
-#ifdef MPACK_MALLOC
-void* mpack_expect_array_alloc_impl(mpack_reader_t* reader, size_t element_size, uint32_t max_count, uint32_t* out_count, bool allow_nil) {
- mpack_assert(out_count != NULL, "out_count cannot be NULL");
- *out_count = 0;
-
- uint32_t count;
- bool has_array = true;
- if (allow_nil)
- has_array = mpack_expect_array_max_or_nil(reader, max_count, &count);
- else
- count = mpack_expect_array_max(reader, max_count);
- if (mpack_reader_error(reader))
- return NULL;
-
- // size 0 is not an error; we return NULL for no elements.
- if (count == 0) {
- // we call mpack_done_array() automatically ONLY if we are using
- // the _or_nil variant. this is the only way to allow nil and empty
- // to work the same way.
- if (allow_nil && has_array)
- mpack_done_array(reader);
- return NULL;
- }
-
- void* p = MPACK_MALLOC(element_size * count);
- if (p == NULL) {
- mpack_reader_flag_error(reader, mpack_error_memory);
- return NULL;
- }
-
- *out_count = count;
- return p;
-}
-#endif
-
-
-// Str, Bin and Ext Functions
-
-uint32_t mpack_expect_str(mpack_reader_t* reader) {
- #if MPACK_OPTIMIZE_FOR_SIZE
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_str)
- return var.v.l;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
- #else
- uint8_t type = mpack_expect_type_byte(reader);
- uint32_t count;
-
- if ((type >> 5) == 5) {
- count = type & (uint8_t)~0xe0;
- } else if (type == 0xd9) {
- count = mpack_expect_native_u8(reader);
- } else if (type == 0xda) {
- count = mpack_expect_native_u16(reader);
- } else if (type == 0xdb) {
- count = mpack_expect_native_u32(reader);
- } else {
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
- }
-
- #if MPACK_READ_TRACKING
- mpack_reader_flag_if_error(reader, mpack_track_push(&reader->track, mpack_type_str, count));
- #endif
- return count;
- #endif
-}
-
-size_t mpack_expect_str_buf(mpack_reader_t* reader, char* buf, size_t bufsize) {
- mpack_assert(buf != NULL, "buf cannot be NULL");
-
- size_t length = mpack_expect_str(reader);
- if (mpack_reader_error(reader))
- return 0;
-
- if (length > bufsize) {
- mpack_reader_flag_error(reader, mpack_error_too_big);
- return 0;
- }
-
- mpack_read_bytes(reader, buf, length);
- if (mpack_reader_error(reader))
- return 0;
-
- mpack_done_str(reader);
- return length;
-}
-
-size_t mpack_expect_utf8(mpack_reader_t* reader, char* buf, size_t size) {
- mpack_assert(buf != NULL, "buf cannot be NULL");
-
- size_t length = mpack_expect_str_buf(reader, buf, size);
-
- if (!mpack_utf8_check(buf, length)) {
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
- }
-
- return length;
-}
-
-uint32_t mpack_expect_bin(mpack_reader_t* reader) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_bin)
- return var.v.l;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-size_t mpack_expect_bin_buf(mpack_reader_t* reader, char* buf, size_t bufsize) {
- mpack_assert(buf != NULL, "buf cannot be NULL");
-
- size_t binsize = mpack_expect_bin(reader);
- if (mpack_reader_error(reader))
- return 0;
- if (binsize > bufsize) {
- mpack_reader_flag_error(reader, mpack_error_too_big);
- return 0;
- }
- mpack_read_bytes(reader, buf, binsize);
- if (mpack_reader_error(reader))
- return 0;
- mpack_done_bin(reader);
- return binsize;
-}
-
-#if MPACK_EXTENSIONS
-uint32_t mpack_expect_ext(mpack_reader_t* reader, int8_t* type) {
- mpack_tag_t var = mpack_read_tag(reader);
- if (var.type == mpack_type_ext) {
- *type = mpack_tag_ext_exttype(&var);
- return mpack_tag_ext_length(&var);
- }
- *type = 0;
- mpack_reader_flag_error(reader, mpack_error_type);
- return 0;
-}
-
-size_t mpack_expect_ext_buf(mpack_reader_t* reader, int8_t* type, char* buf, size_t bufsize) {
- mpack_assert(buf != NULL, "buf cannot be NULL");
-
- size_t extsize = mpack_expect_ext(reader, type);
- if (mpack_reader_error(reader))
- return 0;
- if (extsize > bufsize) {
- *type = 0;
- mpack_reader_flag_error(reader, mpack_error_too_big);
- return 0;
- }
- mpack_read_bytes(reader, buf, extsize);
- if (mpack_reader_error(reader)) {
- *type = 0;
- return 0;
- }
- mpack_done_ext(reader);
- return extsize;
-}
-#endif
-
-void mpack_expect_cstr(mpack_reader_t* reader, char* buf, size_t bufsize) {
- uint32_t length = mpack_expect_str(reader);
- mpack_read_cstr(reader, buf, bufsize, length);
- mpack_done_str(reader);
-}
-
-void mpack_expect_utf8_cstr(mpack_reader_t* reader, char* buf, size_t bufsize) {
- uint32_t length = mpack_expect_str(reader);
- mpack_read_utf8_cstr(reader, buf, bufsize, length);
- mpack_done_str(reader);
-}
-
-#ifdef MPACK_MALLOC
-static char* mpack_expect_cstr_alloc_unchecked(mpack_reader_t* reader, size_t maxsize, size_t* out_length) {
- mpack_assert(out_length != NULL, "out_length cannot be NULL");
- *out_length = 0;
-
- // make sure argument makes sense
- if (maxsize < 1) {
- mpack_break("maxsize is zero; you must have room for at least a null-terminator");
- mpack_reader_flag_error(reader, mpack_error_bug);
- return NULL;
- }
-
- if (maxsize > UINT32_MAX)
- maxsize = UINT32_MAX;
-
- size_t length = mpack_expect_str_max(reader, (uint32_t)maxsize - 1);
- char* str = mpack_read_bytes_alloc_impl(reader, length, true);
- mpack_done_str(reader);
-
- if (str)
- *out_length = length;
- return str;
-}
-
-char* mpack_expect_cstr_alloc(mpack_reader_t* reader, size_t maxsize) {
- size_t length;
- char* str = mpack_expect_cstr_alloc_unchecked(reader, maxsize, &length);
-
- if (str && !mpack_str_check_no_null(str, length)) {
- MPACK_FREE(str);
- mpack_reader_flag_error(reader, mpack_error_type);
- return NULL;
- }
-
- return str;
-}
-
-char* mpack_expect_utf8_cstr_alloc(mpack_reader_t* reader, size_t maxsize) {
- size_t length;
- char* str = mpack_expect_cstr_alloc_unchecked(reader, maxsize, &length);
-
- if (str && !mpack_utf8_check_no_null(str, length)) {
- MPACK_FREE(str);
- mpack_reader_flag_error(reader, mpack_error_type);
- return NULL;
- }
-
- return str;
-}
-#endif
-
-void mpack_expect_str_match(mpack_reader_t* reader, const char* str, size_t len) {
- mpack_assert(str != NULL, "str cannot be NULL");
-
- // expect a str the correct length
- if (len > UINT32_MAX)
- mpack_reader_flag_error(reader, mpack_error_type);
- mpack_expect_str_length(reader, (uint32_t)len);
- if (mpack_reader_error(reader))
- return;
- mpack_reader_track_bytes(reader, len);
-
- // check each byte one by one (matched strings are likely to be very small)
- for (; len > 0; --len) {
- if (mpack_expect_native_u8(reader) != *str++) {
- mpack_reader_flag_error(reader, mpack_error_type);
- return;
- }
- }
-
- mpack_done_str(reader);
-}
-
-void mpack_expect_tag(mpack_reader_t* reader, mpack_tag_t expected) {
- mpack_tag_t actual = mpack_read_tag(reader);
- if (!mpack_tag_equal(actual, expected))
- mpack_reader_flag_error(reader, mpack_error_type);
-}
-
-#ifdef MPACK_MALLOC
-char* mpack_expect_bin_alloc(mpack_reader_t* reader, size_t maxsize, size_t* size) {
- mpack_assert(size != NULL, "size cannot be NULL");
- *size = 0;
-
- if (maxsize > UINT32_MAX)
- maxsize = UINT32_MAX;
-
- size_t length = mpack_expect_bin_max(reader, (uint32_t)maxsize);
- if (mpack_reader_error(reader))
- return NULL;
-
- char* data = mpack_read_bytes_alloc(reader, length);
- mpack_done_bin(reader);
-
- if (data)
- *size = length;
- return data;
-}
-#endif
-
-#if MPACK_EXTENSIONS && defined(MPACK_MALLOC)
-char* mpack_expect_ext_alloc(mpack_reader_t* reader, int8_t* type, size_t maxsize, size_t* size) {
- mpack_assert(size != NULL, "size cannot be NULL");
- *size = 0;
-
- if (maxsize > UINT32_MAX)
- maxsize = UINT32_MAX;
-
- size_t length = mpack_expect_ext_max(reader, type, (uint32_t)maxsize);
- if (mpack_reader_error(reader))
- return NULL;
-
- char* data = mpack_read_bytes_alloc(reader, length);
- mpack_done_ext(reader);
-
- if (data) {
- *size = length;
- } else {
- *type = 0;
- }
- return data;
-}
-#endif
-
-size_t mpack_expect_enum(mpack_reader_t* reader, const char* strings[], size_t count) {
-
- // read the string in-place
- size_t keylen = mpack_expect_str(reader);
- const char* key = mpack_read_bytes_inplace(reader, keylen);
- mpack_done_str(reader);
- if (mpack_reader_error(reader) != mpack_ok)
- return count;
-
- // find what key it matches
- for (size_t i = 0; i < count; ++i) {
- const char* other = strings[i];
- size_t otherlen = mpack_strlen(other);
- if (keylen == otherlen && mpack_memcmp(key, other, keylen) == 0)
- return i;
- }
-
- // no matches
- mpack_reader_flag_error(reader, mpack_error_type);
- return count;
-}
-
-size_t mpack_expect_enum_optional(mpack_reader_t* reader, const char* strings[], size_t count) {
- if (mpack_reader_error(reader) != mpack_ok)
- return count;
-
- mpack_assert(count != 0, "count cannot be zero; no strings are valid!");
- mpack_assert(strings != NULL, "strings cannot be NULL");
-
- // the key is only recognized if it is a string
- if (mpack_peek_tag(reader).type != mpack_type_str) {
- mpack_discard(reader);
- return count;
- }
-
- // read the string in-place
- size_t keylen = mpack_expect_str(reader);
- const char* key = mpack_read_bytes_inplace(reader, keylen);
- mpack_done_str(reader);
- if (mpack_reader_error(reader) != mpack_ok)
- return count;
-
- // find what key it matches
- for (size_t i = 0; i < count; ++i) {
- const char* other = strings[i];
- size_t otherlen = mpack_strlen(other);
- if (keylen == otherlen && mpack_memcmp(key, other, keylen) == 0)
- return i;
- }
-
- // no matches
- return count;
-}
-
-size_t mpack_expect_key_uint(mpack_reader_t* reader, bool found[], size_t count) {
- if (mpack_reader_error(reader) != mpack_ok)
- return count;
-
- if (count == 0) {
- mpack_break("count cannot be zero; no keys are valid!");
- mpack_reader_flag_error(reader, mpack_error_bug);
- return count;
- }
- mpack_assert(found != NULL, "found cannot be NULL");
-
- // the key is only recognized if it is an unsigned int
- if (mpack_peek_tag(reader).type != mpack_type_uint) {
- mpack_discard(reader);
- return count;
- }
-
- // read the key
- uint64_t value = mpack_expect_u64(reader);
- if (mpack_reader_error(reader) != mpack_ok)
- return count;
-
- // unrecognized keys are fine, we just return count
- if (value >= count)
- return count;
-
- // check if this key is a duplicate
- if (found[value]) {
- mpack_reader_flag_error(reader, mpack_error_invalid);
- return count;
- }
-
- found[value] = true;
- return (size_t)value;
-}
-
-size_t mpack_expect_key_cstr(mpack_reader_t* reader, const char* keys[], bool found[], size_t count) {
- size_t i = mpack_expect_enum_optional(reader, keys, count);
-
- // unrecognized keys are fine, we just return count
- if (i == count)
- return count;
-
- // check if this key is a duplicate
- mpack_assert(found != NULL, "found cannot be NULL");
- if (found[i]) {
- mpack_reader_flag_error(reader, mpack_error_invalid);
- return count;
- }
-
- found[i] = true;
- return i;
-}
-
-#endif
-
-
-/* mpack/mpack-node.c.c */
-
-#define MPACK_INTERNAL 1
-
-/* #include "mpack-node.h" */
-
-#if MPACK_NODE
-
-MPACK_STATIC_INLINE const char* mpack_node_data_unchecked(mpack_node_t node) {
- mpack_assert(mpack_node_error(node) == mpack_ok, "tree is in an error state!");
-
- mpack_type_t type = node.data->type;
- MPACK_UNUSED(type);
- #if MPACK_EXTENSIONS
- mpack_assert(type == mpack_type_str || type == mpack_type_bin || type == mpack_type_ext,
- "node of type %i (%s) is not a data type!", type, mpack_type_to_string(type));
- #else
- mpack_assert(type == mpack_type_str || type == mpack_type_bin,
- "node of type %i (%s) is not a data type!", type, mpack_type_to_string(type));
- #endif
-
- return node.tree->data + node.data->value.offset;
-}
-
-#if MPACK_EXTENSIONS
-MPACK_STATIC_INLINE int8_t mpack_node_exttype_unchecked(mpack_node_t node) {
- mpack_assert(mpack_node_error(node) == mpack_ok, "tree is in an error state!");
-
- mpack_type_t type = node.data->type;
- MPACK_UNUSED(type);
- mpack_assert(type == mpack_type_ext, "node of type %i (%s) is not an ext type!",
- type, mpack_type_to_string(type));
-
- // the exttype of an ext node is stored in the byte preceding the data
- return mpack_load_i8(mpack_node_data_unchecked(node) - 1);
-}
-#endif
-
-
-
-/*
- * Tree Parsing
- */
-
-#ifdef MPACK_MALLOC
-
-// fix up the alloc size to make sure it exactly fits the
-// maximum number of nodes it can contain (the allocator will
-// waste it back anyway, but we round it down just in case)
-
-#define MPACK_NODES_PER_PAGE \
- ((MPACK_NODE_PAGE_SIZE - sizeof(mpack_tree_page_t)) / sizeof(mpack_node_data_t) + 1)
-
-#define MPACK_PAGE_ALLOC_SIZE \
- (sizeof(mpack_tree_page_t) + sizeof(mpack_node_data_t) * (MPACK_NODES_PER_PAGE - 1))
-
-#endif
-
-#ifdef MPACK_MALLOC
-/*
- * Fills the tree until we have at least enough bytes for the current node.
- */
-static bool mpack_tree_reserve_fill(mpack_tree_t* tree) {
- mpack_assert(tree->parser.state == mpack_tree_parse_state_in_progress);
-
- size_t bytes = tree->parser.current_node_reserved;
- mpack_assert(bytes > tree->parser.possible_nodes_left,
- "there are already enough bytes! call mpack_tree_ensure() instead.");
- mpack_log("filling to reserve %i bytes\n", (int)bytes);
-
- // if the necessary bytes would put us over the maximum tree
- // size, fail right away.
- // TODO: check for overflow?
- if (tree->data_length + bytes > tree->max_size) {
- mpack_tree_flag_error(tree, mpack_error_too_big);
- return false;
- }
-
- // we'll need a read function to fetch more data. if there's
- // no read function, the data should contain an entire message
- // (or messages), so we flag it as invalid.
- if (tree->read_fn == NULL) {
- mpack_log("tree has no read function!\n");
- mpack_tree_flag_error(tree, mpack_error_invalid);
- return false;
- }
-
- // expand the buffer if needed
- if (tree->data_length + bytes > tree->buffer_capacity) {
-
- // TODO: check for overflow?
- size_t new_capacity = (tree->buffer_capacity == 0) ? MPACK_BUFFER_SIZE : tree->buffer_capacity;
- while (new_capacity < tree->data_length + bytes)
- new_capacity *= 2;
- if (new_capacity > tree->max_size)
- new_capacity = tree->max_size;
-
- mpack_log("expanding buffer from %i to %i\n", (int)tree->buffer_capacity, (int)new_capacity);
-
- char* new_buffer;
- if (tree->buffer == NULL)
- new_buffer = (char*)MPACK_MALLOC(new_capacity);
- else
- new_buffer = (char*)mpack_realloc(tree->buffer, tree->data_length, new_capacity);
-
- if (new_buffer == NULL) {
- mpack_tree_flag_error(tree, mpack_error_memory);
- return false;
- }
-
- tree->data = new_buffer;
- tree->buffer = new_buffer;
- tree->buffer_capacity = new_capacity;
- }
-
- // request as much data as possible, looping until we have
- // all the data we need
- do {
- size_t read = tree->read_fn(tree, tree->buffer + tree->data_length, tree->buffer_capacity - tree->data_length);
-
- // If the fill function encounters an error, it should flag an error on
- // the tree.
- if (mpack_tree_error(tree) != mpack_ok)
- return false;
-
- // We guard against fill functions that return -1 just in case.
- if (read == (size_t)(-1)) {
- mpack_tree_flag_error(tree, mpack_error_io);
- return false;
- }
-
- // If the fill function returns 0, the data is not available yet. We
- // return false to stop parsing the current node.
- if (read == 0) {
- mpack_log("not enough data.\n");
- return false;
- }
-
- mpack_log("read %u more bytes\n", (uint32_t)read);
- tree->data_length += read;
- tree->parser.possible_nodes_left += read;
- } while (tree->parser.possible_nodes_left < bytes);
-
- return true;
-}
-#endif
-
-/*
- * Ensures there are enough additional bytes in the tree for the current node
- * (including reserved bytes for the children of this node, and in addition to
- * the reserved bytes for children of previous compound nodes), reading more
- * data if needed.
- *
- * extra_bytes is the number of additional bytes to reserve for the current
- * node beyond the type byte (since one byte is already reserved for each node
- * by its parent array or map.)
- *
- * This may reallocate the tree, which means the tree->data pointer may change!
- *
- * Returns false if not enough bytes could be read.
- */
-MPACK_STATIC_INLINE bool mpack_tree_reserve_bytes(mpack_tree_t* tree, size_t extra_bytes) {
- mpack_assert(tree->parser.state == mpack_tree_parse_state_in_progress);
-
- // We guard against overflow here. A compound type could declare more than
- // UINT32_MAX contents which overflows SIZE_MAX on 32-bit platforms. We
- // flag mpack_error_invalid instead of mpack_error_too_big since it's far
- // more likely that the message is corrupt than that the data is valid but
- // not parseable on this architecture (see test_read_node_possible() in
- // test-node.c .)
- if ((uint64_t)tree->parser.current_node_reserved + (uint64_t)extra_bytes > SIZE_MAX) {
- mpack_tree_flag_error(tree, mpack_error_invalid);
- return false;
- }
-
- tree->parser.current_node_reserved += extra_bytes;
-
- // Note that possible_nodes_left already accounts for reserved bytes for
- // children of previous compound nodes. So even if there are hundreds of
- // bytes left in the buffer, we might need to read anyway.
- if (tree->parser.current_node_reserved <= tree->parser.possible_nodes_left)
- return true;
-
- #ifdef MPACK_MALLOC
- return mpack_tree_reserve_fill(tree);
- #else
- return false;
- #endif
-}
-
-MPACK_STATIC_INLINE size_t mpack_tree_parser_stack_capacity(mpack_tree_t* tree) {
- #ifdef MPACK_MALLOC
- return tree->parser.stack_capacity;
- #else
- return sizeof(tree->parser.stack) / sizeof(tree->parser.stack[0]);
- #endif
-}
-
-static bool mpack_tree_push_stack(mpack_tree_t* tree, mpack_node_data_t* first_child, size_t total) {
- mpack_tree_parser_t* parser = &tree->parser;
- mpack_assert(parser->state == mpack_tree_parse_state_in_progress);
-
- // No need to push empty containers
- if (total == 0)
- return true;
-
- // Make sure we have enough room in the stack
- if (parser->level + 1 == mpack_tree_parser_stack_capacity(tree)) {
- #ifdef MPACK_MALLOC
- size_t new_capacity = parser->stack_capacity * 2;
- mpack_log("growing parse stack to capacity %i\n", (int)new_capacity);
-
- // Replace the stack-allocated parsing stack
- if (!parser->stack_owned) {
- mpack_level_t* new_stack = (mpack_level_t*)MPACK_MALLOC(sizeof(mpack_level_t) * new_capacity);
- if (!new_stack) {
- mpack_tree_flag_error(tree, mpack_error_memory);
- return false;
- }
- mpack_memcpy(new_stack, parser->stack, sizeof(mpack_level_t) * parser->stack_capacity);
- parser->stack = new_stack;
- parser->stack_owned = true;
-
- // Realloc the allocated parsing stack
- } else {
- mpack_level_t* new_stack = (mpack_level_t*)mpack_realloc(parser->stack,
- sizeof(mpack_level_t) * parser->stack_capacity, sizeof(mpack_level_t) * new_capacity);
- if (!new_stack) {
- mpack_tree_flag_error(tree, mpack_error_memory);
- return false;
- }
- parser->stack = new_stack;
- }
- parser->stack_capacity = new_capacity;
- #else
- mpack_tree_flag_error(tree, mpack_error_too_big);
- return false;
- #endif
- }
-
- // Push the contents of this node onto the parsing stack
- ++parser->level;
- parser->stack[parser->level].child = first_child;
- parser->stack[parser->level].left = total;
- return true;
-}
-
-static bool mpack_tree_parse_children(mpack_tree_t* tree, mpack_node_data_t* node) {
- mpack_tree_parser_t* parser = &tree->parser;
- mpack_assert(parser->state == mpack_tree_parse_state_in_progress);
-
- mpack_type_t type = node->type;
- size_t total = node->len;
-
- // Calculate total elements to read
- if (type == mpack_type_map) {
- if ((uint64_t)total * 2 > SIZE_MAX) {
- mpack_tree_flag_error(tree, mpack_error_too_big);
- return false;
- }
- total *= 2;
- }
-
- // Make sure we are under our total node limit (TODO can this overflow?)
- tree->node_count += total;
- if (tree->node_count > tree->max_nodes) {
- mpack_tree_flag_error(tree, mpack_error_too_big);
- return false;
- }
-
- // Each node is at least one byte. Count these bytes now to make
- // sure there is enough data left.
- if (!mpack_tree_reserve_bytes(tree, total))
- return false;
-
- // If there are enough nodes left in the current page, no need to grow
- if (total <= parser->nodes_left) {
- node->value.children = parser->nodes;
- parser->nodes += total;
- parser->nodes_left -= total;
-
- } else {
-
- #ifdef MPACK_MALLOC
-
- // We can't grow if we're using a fixed pool (i.e. we didn't start with a page)
- if (!tree->next) {
- mpack_tree_flag_error(tree, mpack_error_too_big);
- return false;
- }
-
- // Otherwise we need to grow, and the node's children need to be contiguous.
- // This is a heuristic to decide whether we should waste the remaining space
- // in the current page and start a new one, or give the children their
- // own page. With a fraction of 1/8, this causes at most 12% additional
- // waste. Note that reducing this too much causes less cache coherence and
- // more malloc() overhead due to smaller allocations, so there's a tradeoff
- // here. This heuristic could use some improvement, especially with custom
- // page sizes.
-
- mpack_tree_page_t* page;
-
- if (total > MPACK_NODES_PER_PAGE || parser->nodes_left > MPACK_NODES_PER_PAGE / 8) {
- // TODO: this should check for overflow
- page = (mpack_tree_page_t*)MPACK_MALLOC(
- sizeof(mpack_tree_page_t) + sizeof(mpack_node_data_t) * (total - 1));
- if (page == NULL) {
- mpack_tree_flag_error(tree, mpack_error_memory);
- return false;
- }
- mpack_log("allocated seperate page %p for %i children, %i left in page of %i total\n",
- page, (int)total, (int)parser->nodes_left, (int)MPACK_NODES_PER_PAGE);
-
- node->value.children = page->nodes;
-
- } else {
- page = (mpack_tree_page_t*)MPACK_MALLOC(MPACK_PAGE_ALLOC_SIZE);
- if (page == NULL) {
- mpack_tree_flag_error(tree, mpack_error_memory);
- return false;
- }
- mpack_log("allocated new page %p for %i children, wasting %i in page of %i total\n",
- page, (int)total, (int)parser->nodes_left, (int)MPACK_NODES_PER_PAGE);
-
- node->value.children = page->nodes;
- parser->nodes = page->nodes + total;
- parser->nodes_left = MPACK_NODES_PER_PAGE - total;
- }
-
- page->next = tree->next;
- tree->next = page;
-
- #else
- // We can't grow if we don't have an allocator
- mpack_tree_flag_error(tree, mpack_error_too_big);
- return false;
- #endif
- }
-
- return mpack_tree_push_stack(tree, node->value.children, total);
-}
-
-static bool mpack_tree_parse_bytes(mpack_tree_t* tree, mpack_node_data_t* node) {
- node->value.offset = tree->size + tree->parser.current_node_reserved + 1;
- return mpack_tree_reserve_bytes(tree, node->len);
-}
-
-#if MPACK_EXTENSIONS
-static bool mpack_tree_parse_ext(mpack_tree_t* tree, mpack_node_data_t* node) {
- // reserve space for exttype
- tree->parser.current_node_reserved += sizeof(int8_t);
- node->type = mpack_type_ext;
- return mpack_tree_parse_bytes(tree, node);
-}
-#endif
-
-static bool mpack_tree_parse_node_contents(mpack_tree_t* tree, mpack_node_data_t* node) {
- mpack_assert(tree->parser.state == mpack_tree_parse_state_in_progress);
- mpack_assert(node != NULL, "null node?");
-
- // read the type. we've already accounted for this byte in
- // possible_nodes_left, so we already know it is in bounds, and we don't
- // need to reserve it for this node.
- mpack_assert(tree->data_length > tree->size);
- uint8_t type = mpack_load_u8(tree->data + tree->size);
- mpack_log("node type %x\n", type);
- tree->parser.current_node_reserved = 0;
-
- // as with mpack_read_tag(), the fastest way to parse a node is to switch
- // on the first byte, and to explicitly list every possible byte. we switch
- // on the first four bits in size-optimized builds.
-
- #if MPACK_OPTIMIZE_FOR_SIZE
- switch (type >> 4) {
-
- // positive fixnum
- case 0x0: case 0x1: case 0x2: case 0x3:
- case 0x4: case 0x5: case 0x6: case 0x7:
- node->type = mpack_type_uint;
- node->value.u = type;
- return true;
-
- // negative fixnum
- case 0xe: case 0xf:
- node->type = mpack_type_int;
- node->value.i = (int8_t)type;
- return true;
-
- // fixmap
- case 0x8:
- node->type = mpack_type_map;
- node->len = (uint32_t)(type & ~0xf0);
- return mpack_tree_parse_children(tree, node);
-
- // fixarray
- case 0x9:
- node->type = mpack_type_array;
- node->len = (uint32_t)(type & ~0xf0);
- return mpack_tree_parse_children(tree, node);
-
- // fixstr
- case 0xa: case 0xb:
- node->type = mpack_type_str;
- node->len = (uint32_t)(type & ~0xe0);
- return mpack_tree_parse_bytes(tree, node);
-
- // not one of the common infix types
- default:
- break;
- }
- #endif
-
- switch (type) {
-
- #if !MPACK_OPTIMIZE_FOR_SIZE
- // positive fixnum
- case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
- case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
- case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
- case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
- case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
- case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
- case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
- case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
- case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
- case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
- case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
- case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
- case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
- node->type = mpack_type_uint;
- node->value.u = type;
- return true;
-
- // negative fixnum
- case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
- case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
- case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
- case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
- node->type = mpack_type_int;
- node->value.i = (int8_t)type;
- return true;
-
- // fixmap
- case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
- case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
- node->type = mpack_type_map;
- node->len = (uint32_t)(type & ~0xf0);
- return mpack_tree_parse_children(tree, node);
-
- // fixarray
- case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
- case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
- node->type = mpack_type_array;
- node->len = (uint32_t)(type & ~0xf0);
- return mpack_tree_parse_children(tree, node);
-
- // fixstr
- case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
- case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
- case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
- case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
- node->type = mpack_type_str;
- node->len = (uint32_t)(type & ~0xe0);
- return mpack_tree_parse_bytes(tree, node);
- #endif
-
- // nil
- case 0xc0:
- node->type = mpack_type_nil;
- return true;
-
- // bool
- case 0xc2: case 0xc3:
- node->type = mpack_type_bool;
- node->value.b = type & 1;
- return true;
-
- // bin8
- case 0xc4:
- node->type = mpack_type_bin;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
- return false;
- node->len = mpack_load_u8(tree->data + tree->size + 1);
- return mpack_tree_parse_bytes(tree, node);
-
- // bin16
- case 0xc5:
- node->type = mpack_type_bin;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
- return false;
- node->len = mpack_load_u16(tree->data + tree->size + 1);
- return mpack_tree_parse_bytes(tree, node);
-
- // bin32
- case 0xc6:
- node->type = mpack_type_bin;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
- return false;
- node->len = mpack_load_u32(tree->data + tree->size + 1);
- return mpack_tree_parse_bytes(tree, node);
-
- #if MPACK_EXTENSIONS
- // ext8
- case 0xc7:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
- return false;
- node->len = mpack_load_u8(tree->data + tree->size + 1);
- return mpack_tree_parse_ext(tree, node);
-
- // ext16
- case 0xc8:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
- return false;
- node->len = mpack_load_u16(tree->data + tree->size + 1);
- return mpack_tree_parse_ext(tree, node);
-
- // ext32
- case 0xc9:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
- return false;
- node->len = mpack_load_u32(tree->data + tree->size + 1);
- return mpack_tree_parse_ext(tree, node);
- #endif
-
- // float
- case 0xca:
- if (!mpack_tree_reserve_bytes(tree, sizeof(float)))
- return false;
- node->value.f = mpack_load_float(tree->data + tree->size + 1);
- node->type = mpack_type_float;
- return true;
-
- // double
- case 0xcb:
- if (!mpack_tree_reserve_bytes(tree, sizeof(double)))
- return false;
- node->value.d = mpack_load_double(tree->data + tree->size + 1);
- node->type = mpack_type_double;
- return true;
-
- // uint8
- case 0xcc:
- node->type = mpack_type_uint;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
- return false;
- node->value.u = mpack_load_u8(tree->data + tree->size + 1);
- return true;
-
- // uint16
- case 0xcd:
- node->type = mpack_type_uint;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
- return false;
- node->value.u = mpack_load_u16(tree->data + tree->size + 1);
- return true;
-
- // uint32
- case 0xce:
- node->type = mpack_type_uint;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
- return false;
- node->value.u = mpack_load_u32(tree->data + tree->size + 1);
- return true;
-
- // uint64
- case 0xcf:
- node->type = mpack_type_uint;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint64_t)))
- return false;
- node->value.u = mpack_load_u64(tree->data + tree->size + 1);
- return true;
-
- // int8
- case 0xd0:
- node->type = mpack_type_int;
- if (!mpack_tree_reserve_bytes(tree, sizeof(int8_t)))
- return false;
- node->value.i = mpack_load_i8(tree->data + tree->size + 1);
- return true;
-
- // int16
- case 0xd1:
- node->type = mpack_type_int;
- if (!mpack_tree_reserve_bytes(tree, sizeof(int16_t)))
- return false;
- node->value.i = mpack_load_i16(tree->data + tree->size + 1);
- return true;
-
- // int32
- case 0xd2:
- node->type = mpack_type_int;
- if (!mpack_tree_reserve_bytes(tree, sizeof(int32_t)))
- return false;
- node->value.i = mpack_load_i32(tree->data + tree->size + 1);
- return true;
-
- // int64
- case 0xd3:
- node->type = mpack_type_int;
- if (!mpack_tree_reserve_bytes(tree, sizeof(int64_t)))
- return false;
- node->value.i = mpack_load_i64(tree->data + tree->size + 1);
- return true;
-
- #if MPACK_EXTENSIONS
- // fixext1
- case 0xd4:
- node->len = 1;
- return mpack_tree_parse_ext(tree, node);
-
- // fixext2
- case 0xd5:
- node->len = 2;
- return mpack_tree_parse_ext(tree, node);
-
- // fixext4
- case 0xd6:
- node->len = 4;
- return mpack_tree_parse_ext(tree, node);
-
- // fixext8
- case 0xd7:
- node->len = 8;
- return mpack_tree_parse_ext(tree, node);
-
- // fixext16
- case 0xd8:
- node->len = 16;
- return mpack_tree_parse_ext(tree, node);
- #endif
-
- // str8
- case 0xd9:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
- return false;
- node->len = mpack_load_u8(tree->data + tree->size + 1);
- node->type = mpack_type_str;
- return mpack_tree_parse_bytes(tree, node);
-
- // str16
- case 0xda:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
- return false;
- node->len = mpack_load_u16(tree->data + tree->size + 1);
- node->type = mpack_type_str;
- return mpack_tree_parse_bytes(tree, node);
-
- // str32
- case 0xdb:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
- return false;
- node->len = mpack_load_u32(tree->data + tree->size + 1);
- node->type = mpack_type_str;
- return mpack_tree_parse_bytes(tree, node);
-
- // array16
- case 0xdc:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
- return false;
- node->len = mpack_load_u16(tree->data + tree->size + 1);
- node->type = mpack_type_array;
- return mpack_tree_parse_children(tree, node);
-
- // array32
- case 0xdd:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
- return false;
- node->len = mpack_load_u32(tree->data + tree->size + 1);
- node->type = mpack_type_array;
- return mpack_tree_parse_children(tree, node);
-
- // map16
- case 0xde:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
- return false;
- node->len = mpack_load_u16(tree->data + tree->size + 1);
- node->type = mpack_type_map;
- return mpack_tree_parse_children(tree, node);
-
- // map32
- case 0xdf:
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
- return false;
- node->len = mpack_load_u32(tree->data + tree->size + 1);
- node->type = mpack_type_map;
- return mpack_tree_parse_children(tree, node);
-
- // reserved
- case 0xc1:
- mpack_tree_flag_error(tree, mpack_error_invalid);
- return false;
-
- #if !MPACK_EXTENSIONS
- // ext
- case 0xc7: // fallthrough
- case 0xc8: // fallthrough
- case 0xc9: // fallthrough
- // fixext
- case 0xd4: // fallthrough
- case 0xd5: // fallthrough
- case 0xd6: // fallthrough
- case 0xd7: // fallthrough
- case 0xd8:
- mpack_tree_flag_error(tree, mpack_error_unsupported);
- return false;
- #endif
-
- #if MPACK_OPTIMIZE_FOR_SIZE
- // any other bytes should have been handled by the infix switch
- default:
- break;
- #endif
- }
-
- mpack_assert(0, "unreachable");
- return false;
-}
-
-static bool mpack_tree_parse_node(mpack_tree_t* tree, mpack_node_data_t* node) {
- mpack_log("parsing a node at position %i in level %i\n",
- (int)tree->size, (int)tree->parser.level);
-
- if (!mpack_tree_parse_node_contents(tree, node)) {
- mpack_log("node parsing returned false\n");
- return false;
- }
-
- tree->parser.possible_nodes_left -= tree->parser.current_node_reserved;
-
- // The reserve for the current node does not include the initial byte
- // previously reserved as part of its parent.
- size_t node_size = tree->parser.current_node_reserved + 1;
-
- // If the parsed type is a map or array, the reserve includes one byte for
- // each child. We want to subtract these out of possible_nodes_left, but
- // not out of the current size of the tree.
- if (node->type == mpack_type_array)
- node_size -= node->len;
- else if (node->type == mpack_type_map)
- node_size -= node->len * 2;
- tree->size += node_size;
-
- mpack_log("parsed a node of type %s of %i bytes and "
- "%i additional bytes reserved for children.\n",
- mpack_type_to_string(node->type), (int)node_size,
- (int)tree->parser.current_node_reserved + 1 - (int)node_size);
-
- return true;
-}
-
-/*
- * We read nodes in a loop instead of recursively for maximum performance. The
- * stack holds the amount of children left to read in each level of the tree.
- * Parsing can pause and resume when more data becomes available.
- */
-static bool mpack_tree_continue_parsing(mpack_tree_t* tree) {
- if (mpack_tree_error(tree) != mpack_ok)
- return false;
-
- mpack_tree_parser_t* parser = &tree->parser;
- mpack_assert(parser->state == mpack_tree_parse_state_in_progress);
- mpack_log("parsing tree elements, %i bytes in buffer\n", (int)tree->data_length);
-
- // we loop parsing nodes until the parse stack is empty. we break
- // by returning out of the function.
- while (true) {
- mpack_node_data_t* node = parser->stack[parser->level].child;
- size_t level = parser->level;
- if (!mpack_tree_parse_node(tree, node))
- return false;
- --parser->stack[level].left;
- ++parser->stack[level].child;
-
- mpack_assert(mpack_tree_error(tree) == mpack_ok,
- "mpack_tree_parse_node() should have returned false due to error!");
-
- // pop empty stack levels, exiting the outer loop when the stack is empty.
- // (we could tail-optimize containers by pre-emptively popping empty
- // stack levels before reading the new element, this way we wouldn't
- // have to loop. but we eventually want to use the parse stack to give
- // better error messages that contain the location of the error, so
- // it needs to be complete.)
- while (parser->stack[parser->level].left == 0) {
- if (parser->level == 0)
- return true;
- --parser->level;
- }
- }
-}
-
-static void mpack_tree_cleanup(mpack_tree_t* tree) {
- MPACK_UNUSED(tree);
-
- #ifdef MPACK_MALLOC
- if (tree->parser.stack_owned) {
- MPACK_FREE(tree->parser.stack);
- tree->parser.stack = NULL;
- tree->parser.stack_owned = false;
- }
-
- mpack_tree_page_t* page = tree->next;
- while (page != NULL) {
- mpack_tree_page_t* next = page->next;
- mpack_log("freeing page %p\n", page);
- MPACK_FREE(page);
- page = next;
- }
- tree->next = NULL;
- #endif
-}
-
-static bool mpack_tree_parse_start(mpack_tree_t* tree) {
- if (mpack_tree_error(tree) != mpack_ok)
- return false;
-
- mpack_tree_parser_t* parser = &tree->parser;
- mpack_assert(parser->state != mpack_tree_parse_state_in_progress,
- "previous parsing was not finished!");
-
- if (parser->state == mpack_tree_parse_state_parsed)
- mpack_tree_cleanup(tree);
-
- mpack_log("starting parse\n");
- tree->parser.state = mpack_tree_parse_state_in_progress;
- tree->parser.current_node_reserved = 0;
-
- // check if we previously parsed a tree
- if (tree->size > 0) {
- #ifdef MPACK_MALLOC
- // if we're buffered, move the remaining data back to the
- // start of the buffer
- // TODO: This is not ideal performance-wise. We should only move data
- // when we need to call the fill function.
- // TODO: We could consider shrinking the buffer here, especially if we
- // determine that the fill function is providing less than a quarter of
- // the buffer size or if messages take up less than a quarter of the
- // buffer size. Maybe this should be configurable.
- if (tree->buffer != NULL) {
- mpack_memmove(tree->buffer, tree->buffer + tree->size, tree->data_length - tree->size);
- }
- else
- #endif
- // otherwise advance past the parsed data
- {
- tree->data += tree->size;
- }
- tree->data_length -= tree->size;
- tree->size = 0;
- tree->node_count = 0;
- }
-
- // make sure we have at least one byte available before allocating anything
- parser->possible_nodes_left = tree->data_length;
- if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t))) {
- tree->parser.state = mpack_tree_parse_state_not_started;
- return false;
- }
- mpack_log("parsing tree at %p starting with byte %x\n", tree->data, (uint8_t)tree->data[0]);
- parser->possible_nodes_left -= 1;
- tree->node_count = 1;
-
- #ifdef MPACK_MALLOC
- parser->stack = parser->stack_local;
- parser->stack_owned = false;
- parser->stack_capacity = sizeof(parser->stack_local) / sizeof(*parser->stack_local);
-
- if (tree->pool == NULL) {
-
- // allocate first page
- mpack_tree_page_t* page = (mpack_tree_page_t*)MPACK_MALLOC(MPACK_PAGE_ALLOC_SIZE);
- mpack_log("allocated initial page %p of size %i count %i\n",
- page, (int)MPACK_PAGE_ALLOC_SIZE, (int)MPACK_NODES_PER_PAGE);
- if (page == NULL) {
- tree->error = mpack_error_memory;
- return false;
- }
- page->next = NULL;
- tree->next = page;
-
- parser->nodes = page->nodes;
- parser->nodes_left = MPACK_NODES_PER_PAGE;
- }
- else
- #endif
- {
- // otherwise use the provided pool
- mpack_assert(tree->pool != NULL, "no pool provided?");
- parser->nodes = tree->pool;
- parser->nodes_left = tree->pool_count;
- }
-
- tree->root = parser->nodes;
- ++parser->nodes;
- --parser->nodes_left;
-
- parser->level = 0;
- parser->stack[0].child = tree->root;
- parser->stack[0].left = 1;
-
- return true;
-}
-
-void mpack_tree_parse(mpack_tree_t* tree) {
- if (mpack_tree_error(tree) != mpack_ok)
- return;
-
- if (tree->parser.state != mpack_tree_parse_state_in_progress) {
- if (!mpack_tree_parse_start(tree)) {
- mpack_tree_flag_error(tree, (tree->read_fn == NULL) ?
- mpack_error_invalid : mpack_error_io);
- return;
- }
- }
-
- if (!mpack_tree_continue_parsing(tree)) {
- if (mpack_tree_error(tree) != mpack_ok)
- return;
-
- // We're parsing synchronously on a blocking fill function. If we
- // didn't completely finish parsing the tree, it's an error.
- mpack_log("tree parsing incomplete. flagging error.\n");
- mpack_tree_flag_error(tree, (tree->read_fn == NULL) ?
- mpack_error_invalid : mpack_error_io);
- return;
- }
-
- mpack_assert(mpack_tree_error(tree) == mpack_ok);
- mpack_assert(tree->parser.level == 0);
- tree->parser.state = mpack_tree_parse_state_parsed;
- mpack_log("parsed tree of %i bytes, %i bytes left\n", (int)tree->size, (int)tree->parser.possible_nodes_left);
- mpack_log("%i nodes in final page\n", (int)tree->parser.nodes_left);
-}
-
-bool mpack_tree_try_parse(mpack_tree_t* tree) {
- if (mpack_tree_error(tree) != mpack_ok)
- return false;
-
- if (tree->parser.state != mpack_tree_parse_state_in_progress)
- if (!mpack_tree_parse_start(tree))
- return false;
-
- if (!mpack_tree_continue_parsing(tree))
- return false;
-
- mpack_assert(mpack_tree_error(tree) == mpack_ok);
- mpack_assert(tree->parser.level == 0);
- tree->parser.state = mpack_tree_parse_state_parsed;
- return true;
-}
-
-
-
-/*
- * Tree functions
- */
-
-mpack_node_t mpack_tree_root(mpack_tree_t* tree) {
- if (mpack_tree_error(tree) != mpack_ok)
- return mpack_tree_nil_node(tree);
-
- // We check that a tree was parsed successfully and assert if not. You must
- // call mpack_tree_parse() (or mpack_tree_try_parse() with a success
- // result) in order to access the root node.
- if (tree->parser.state != mpack_tree_parse_state_parsed) {
- mpack_break("Tree has not been parsed! "
- "Did you call mpack_tree_parse() or mpack_tree_try_parse()?");
- mpack_tree_flag_error(tree, mpack_error_bug);
- return mpack_tree_nil_node(tree);
- }
-
- return mpack_node(tree, tree->root);
-}
-
-static void mpack_tree_init_clear(mpack_tree_t* tree) {
- mpack_memset(tree, 0, sizeof(*tree));
- tree->nil_node.type = mpack_type_nil;
- tree->missing_node.type = mpack_type_missing;
- tree->max_size = SIZE_MAX;
- tree->max_nodes = SIZE_MAX;
-}
-
-#ifdef MPACK_MALLOC
-void mpack_tree_init_data(mpack_tree_t* tree, const char* data, size_t length) {
- mpack_tree_init_clear(tree);
-
- MPACK_STATIC_ASSERT(MPACK_NODE_PAGE_SIZE >= sizeof(mpack_tree_page_t),
- "MPACK_NODE_PAGE_SIZE is too small");
-
- MPACK_STATIC_ASSERT(MPACK_PAGE_ALLOC_SIZE <= MPACK_NODE_PAGE_SIZE,
- "incorrect page rounding?");
-
- tree->data = data;
- tree->data_length = length;
- tree->pool = NULL;
- tree->pool_count = 0;
- tree->next = NULL;
-
- mpack_log("===========================\n");
- mpack_log("initializing tree with data of size %i\n", (int)length);
-}
-#endif
-
-void mpack_tree_init_pool(mpack_tree_t* tree, const char* data, size_t length,
- mpack_node_data_t* node_pool, size_t node_pool_count)
-{
- mpack_tree_init_clear(tree);
- #ifdef MPACK_MALLOC
- tree->next = NULL;
- #endif
-
- if (node_pool_count == 0) {
- mpack_break("initial page has no nodes!");
- mpack_tree_flag_error(tree, mpack_error_bug);
- return;
- }
-
- tree->data = data;
- tree->data_length = length;
- tree->pool = node_pool;
- tree->pool_count = node_pool_count;
-
- mpack_log("===========================\n");
- mpack_log("initializing tree with data of size %i and pool of count %i\n",
- (int)length, (int)node_pool_count);
-}
-
-void mpack_tree_init_error(mpack_tree_t* tree, mpack_error_t error) {
- mpack_tree_init_clear(tree);
- tree->error = error;
-
- mpack_log("===========================\n");
- mpack_log("initializing tree error state %i\n", (int)error);
-}
-
-#ifdef MPACK_MALLOC
-void mpack_tree_init_stream(mpack_tree_t* tree, mpack_tree_read_t read_fn, void* context,
- size_t max_message_size, size_t max_message_nodes) {
- mpack_tree_init_clear(tree);
-
- tree->read_fn = read_fn;
- tree->context = context;
-
- mpack_tree_set_limits(tree, max_message_size, max_message_nodes);
- tree->max_size = max_message_size;
- tree->max_nodes = max_message_nodes;
-
- mpack_log("===========================\n");
- mpack_log("initializing tree with stream, max size %i max nodes %i\n",
- (int)max_message_size, (int)max_message_nodes);
-}
-#endif
-
-void mpack_tree_set_limits(mpack_tree_t* tree, size_t max_message_size, size_t max_message_nodes) {
- mpack_assert(max_message_size > 0);
- mpack_assert(max_message_nodes > 0);
- tree->max_size = max_message_size;
- tree->max_nodes = max_message_nodes;
-}
-
-#if MPACK_STDIO
-typedef struct mpack_file_tree_t {
- char* data;
- size_t size;
- char buffer[MPACK_BUFFER_SIZE];
-} mpack_file_tree_t;
-
-static void mpack_file_tree_teardown(mpack_tree_t* tree) {
- mpack_file_tree_t* file_tree = (mpack_file_tree_t*)tree->context;
- MPACK_FREE(file_tree->data);
- MPACK_FREE(file_tree);
-}
-
-static bool mpack_file_tree_read(mpack_tree_t* tree, mpack_file_tree_t* file_tree, FILE* file, size_t max_bytes) {
-
- // get the file size
- errno = 0;
- int error = 0;
- fseek(file, 0, SEEK_END);
- error |= errno;
- long size = ftell(file);
- error |= errno;
- fseek(file, 0, SEEK_SET);
- error |= errno;
-
- // check for errors
- if (error != 0 || size < 0) {
- mpack_tree_init_error(tree, mpack_error_io);
- return false;
- }
- if (size == 0) {
- mpack_tree_init_error(tree, mpack_error_invalid);
- return false;
- }
-
- // make sure the size is less than max_bytes
- // (this mess exists to safely convert between long and size_t regardless of their widths)
- if (max_bytes != 0 && (((uint64_t)LONG_MAX > (uint64_t)SIZE_MAX && size > (long)SIZE_MAX) || (size_t)size > max_bytes)) {
- mpack_tree_init_error(tree, mpack_error_too_big);
- return false;
- }
-
- // allocate data
- file_tree->data = (char*)MPACK_MALLOC((size_t)size);
- if (file_tree->data == NULL) {
- mpack_tree_init_error(tree, mpack_error_memory);
- return false;
- }
-
- // read the file
- long total = 0;
- while (total < size) {
- size_t read = fread(file_tree->data + total, 1, (size_t)(size - total), file);
- if (read <= 0) {
- mpack_tree_init_error(tree, mpack_error_io);
- MPACK_FREE(file_tree->data);
- return false;
- }
- total += (long)read;
- }
-
- file_tree->size = (size_t)size;
- return true;
-}
-
-static bool mpack_tree_file_check_max_bytes(mpack_tree_t* tree, size_t max_bytes) {
-
- // the C STDIO family of file functions use long (e.g. ftell)
- if (max_bytes > LONG_MAX) {
- mpack_break("max_bytes of %" PRIu64 " is invalid, maximum is LONG_MAX", (uint64_t)max_bytes);
- mpack_tree_init_error(tree, mpack_error_bug);
- return false;
- }
-
- return true;
-}
-
-static void mpack_tree_init_stdfile_noclose(mpack_tree_t* tree, FILE* stdfile, size_t max_bytes) {
-
- // allocate file tree
- mpack_file_tree_t* file_tree = (mpack_file_tree_t*) MPACK_MALLOC(sizeof(mpack_file_tree_t));
- if (file_tree == NULL) {
- mpack_tree_init_error(tree, mpack_error_memory);
- return;
- }
-
- // read all data
- if (!mpack_file_tree_read(tree, file_tree, stdfile, max_bytes)) {
- MPACK_FREE(file_tree);
- return;
- }
-
- mpack_tree_init_data(tree, file_tree->data, file_tree->size);
- mpack_tree_set_context(tree, file_tree);
- mpack_tree_set_teardown(tree, mpack_file_tree_teardown);
-}
-
-void mpack_tree_init_stdfile(mpack_tree_t* tree, FILE* stdfile, size_t max_bytes, bool close_when_done) {
- if (!mpack_tree_file_check_max_bytes(tree, max_bytes))
- return;
-
- mpack_tree_init_stdfile_noclose(tree, stdfile, max_bytes);
-
- if (close_when_done)
- fclose(stdfile);
-}
-
-void mpack_tree_init_filename(mpack_tree_t* tree, const char* filename, size_t max_bytes) {
- if (!mpack_tree_file_check_max_bytes(tree, max_bytes))
- return;
-
- // open the file
- FILE* file = fopen(filename, "rb");
- if (!file) {
- mpack_tree_init_error(tree, mpack_error_io);
- return;
- }
-
- mpack_tree_init_stdfile(tree, file, max_bytes, true);
-}
-#endif
-
-mpack_error_t mpack_tree_destroy(mpack_tree_t* tree) {
- mpack_tree_cleanup(tree);
-
- #ifdef MPACK_MALLOC
- if (tree->buffer)
- MPACK_FREE(tree->buffer);
- #endif
-
- if (tree->teardown)
- tree->teardown(tree);
- tree->teardown = NULL;
-
- return tree->error;
-}
-
-void mpack_tree_flag_error(mpack_tree_t* tree, mpack_error_t error) {
- if (tree->error == mpack_ok) {
- mpack_log("tree %p setting error %i: %s\n", tree, (int)error, mpack_error_to_string(error));
- tree->error = error;
- if (tree->error_fn)
- tree->error_fn(tree, error);
- }
-
-}
-
-
-
-/*
- * Node misc functions
- */
-
-void mpack_node_flag_error(mpack_node_t node, mpack_error_t error) {
- mpack_tree_flag_error(node.tree, error);
-}
-
-mpack_tag_t mpack_node_tag(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return mpack_tag_nil();
-
- mpack_tag_t tag = MPACK_TAG_ZERO;
-
- tag.type = node.data->type;
- switch (node.data->type) {
- case mpack_type_missing:
- // If a node is missing, I don't know if it makes sense to ask for
- // a tag for it. We'll return a missing tag to match the missing
- // node I guess, but attempting to use the tag for anything (like
- // writing it for example) will flag mpack_error_bug.
- break;
- case mpack_type_nil: break;
- case mpack_type_bool: tag.v.b = node.data->value.b; break;
- case mpack_type_float: tag.v.f = node.data->value.f; break;
- case mpack_type_double: tag.v.d = node.data->value.d; break;
- case mpack_type_int: tag.v.i = node.data->value.i; break;
- case mpack_type_uint: tag.v.u = node.data->value.u; break;
-
- case mpack_type_str: tag.v.l = node.data->len; break;
- case mpack_type_bin: tag.v.l = node.data->len; break;
-
- #if MPACK_EXTENSIONS
- case mpack_type_ext:
- tag.v.l = node.data->len;
- tag.exttype = mpack_node_exttype_unchecked(node);
- break;
- #endif
-
- case mpack_type_array: tag.v.n = node.data->len; break;
- case mpack_type_map: tag.v.n = node.data->len; break;
-
- default:
- mpack_assert(0, "unrecognized type %i", (int)node.data->type);
- break;
- }
- return tag;
-}
-
-#if MPACK_DEBUG && MPACK_STDIO
-static void mpack_node_print_element(mpack_node_t node, mpack_print_t* print, size_t depth) {
- mpack_node_data_t* data = node.data;
- switch (data->type) {
- case mpack_type_str:
- {
- mpack_print_append_cstr(print, "\"");
- const char* bytes = mpack_node_data_unchecked(node);
- for (size_t i = 0; i < data->len; ++i) {
- char c = bytes[i];
- switch (c) {
- case '\n': mpack_print_append_cstr(print, "\\n"); break;
- case '\\': mpack_print_append_cstr(print, "\\\\"); break;
- case '"': mpack_print_append_cstr(print, "\\\""); break;
- default: mpack_print_append(print, &c, 1); break;
- }
- }
- mpack_print_append_cstr(print, "\"");
- }
- break;
-
- case mpack_type_array:
- mpack_print_append_cstr(print, "[\n");
- for (size_t i = 0; i < data->len; ++i) {
- for (size_t j = 0; j < depth + 1; ++j)
- mpack_print_append_cstr(print, " ");
- mpack_node_print_element(mpack_node_array_at(node, i), print, depth + 1);
- if (i != data->len - 1)
- mpack_print_append_cstr(print, ",");
- mpack_print_append_cstr(print, "\n");
- }
- for (size_t i = 0; i < depth; ++i)
- mpack_print_append_cstr(print, " ");
- mpack_print_append_cstr(print, "]");
- break;
-
- case mpack_type_map:
- mpack_print_append_cstr(print, "{\n");
- for (size_t i = 0; i < data->len; ++i) {
- for (size_t j = 0; j < depth + 1; ++j)
- mpack_print_append_cstr(print, " ");
- mpack_node_print_element(mpack_node_map_key_at(node, i), print, depth + 1);
- mpack_print_append_cstr(print, ": ");
- mpack_node_print_element(mpack_node_map_value_at(node, i), print, depth + 1);
- if (i != data->len - 1)
- mpack_print_append_cstr(print, ",");
- mpack_print_append_cstr(print, "\n");
- }
- for (size_t i = 0; i < depth; ++i)
- mpack_print_append_cstr(print, " ");
- mpack_print_append_cstr(print, "}");
- break;
-
- default:
- {
- const char* prefix = NULL;
- size_t prefix_length = 0;
- if (mpack_node_type(node) == mpack_type_bin
- #if MPACK_EXTENSIONS
- || mpack_node_type(node) == mpack_type_ext
- #endif
- ) {
- prefix = mpack_node_data(node);
- prefix_length = mpack_node_data_len(node);
- }
-
- char buf[256];
- mpack_tag_t tag = mpack_node_tag(node);
- mpack_tag_debug_pseudo_json(tag, buf, sizeof(buf), prefix, prefix_length);
- mpack_print_append_cstr(print, buf);
- }
- break;
- }
-}
-
-void mpack_node_print_to_buffer(mpack_node_t node, char* buffer, size_t buffer_size) {
- if (buffer_size == 0) {
- mpack_assert(false, "buffer size is zero!");
- return;
- }
-
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = buffer_size;
- mpack_node_print_element(node, &print, 0);
- mpack_print_append(&print, "", 1); // null-terminator
- mpack_print_flush(&print);
-
- // we always make sure there's a null-terminator at the end of the buffer
- // in case we ran out of space.
- print.buffer[print.size - 1] = '\0';
-}
-
-void mpack_node_print_to_callback(mpack_node_t node, mpack_print_callback_t callback, void* context) {
- char buffer[1024];
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = sizeof(buffer);
- print.callback = callback;
- print.context = context;
- mpack_node_print_element(node, &print, 0);
- mpack_print_flush(&print);
-}
-
-void mpack_node_print_to_file(mpack_node_t node, FILE* file) {
- mpack_assert(file != NULL, "file is NULL");
-
- char buffer[1024];
- mpack_print_t print;
- mpack_memset(&print, 0, sizeof(print));
- print.buffer = buffer;
- print.size = sizeof(buffer);
- print.callback = &mpack_print_file_callback;
- print.context = file;
-
- size_t depth = 2;
- for (size_t i = 0; i < depth; ++i)
- mpack_print_append_cstr(&print, " ");
- mpack_node_print_element(node, &print, depth);
- mpack_print_append_cstr(&print, "\n");
- mpack_print_flush(&print);
-}
-#endif
-
-
-
-/*
- * Node Value Functions
- */
-
-#if MPACK_EXTENSIONS
-mpack_timestamp_t mpack_node_timestamp(mpack_node_t node) {
- mpack_timestamp_t timestamp = {0, 0};
-
- // we'll let mpack_node_exttype() do most checks
- if (mpack_node_exttype(node) != MPACK_EXTTYPE_TIMESTAMP) {
- mpack_log("exttype %i\n", mpack_node_exttype(node));
- mpack_node_flag_error(node, mpack_error_type);
- return timestamp;
- }
-
- const char* p = mpack_node_data_unchecked(node);
-
- switch (node.data->len) {
- case 4:
- timestamp.nanoseconds = 0;
- timestamp.seconds = mpack_load_u32(p);
- break;
-
- case 8: {
- uint64_t value = mpack_load_u64(p);
- timestamp.nanoseconds = (uint32_t)(value >> 34);
- timestamp.seconds = value & ((UINT64_C(1) << 34) - 1);
- break;
- }
-
- case 12:
- timestamp.nanoseconds = mpack_load_u32(p);
- timestamp.seconds = mpack_load_i64(p + 4);
- break;
-
- default:
- mpack_tree_flag_error(node.tree, mpack_error_invalid);
- return timestamp;
- }
-
- if (timestamp.nanoseconds > MPACK_TIMESTAMP_NANOSECONDS_MAX) {
- mpack_tree_flag_error(node.tree, mpack_error_invalid);
- mpack_timestamp_t zero = {0, 0};
- return zero;
- }
-
- return timestamp;
-}
-
-int64_t mpack_node_timestamp_seconds(mpack_node_t node) {
- return mpack_node_timestamp(node).seconds;
-}
-
-uint32_t mpack_node_timestamp_nanoseconds(mpack_node_t node) {
- return mpack_node_timestamp(node).nanoseconds;
-}
-#endif
-
-
-
-/*
- * Node Data Functions
- */
-
-void mpack_node_check_utf8(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return;
- mpack_node_data_t* data = node.data;
- if (data->type != mpack_type_str || !mpack_utf8_check(mpack_node_data_unchecked(node), data->len))
- mpack_node_flag_error(node, mpack_error_type);
-}
-
-void mpack_node_check_utf8_cstr(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return;
- mpack_node_data_t* data = node.data;
- if (data->type != mpack_type_str || !mpack_utf8_check_no_null(mpack_node_data_unchecked(node), data->len))
- mpack_node_flag_error(node, mpack_error_type);
-}
-
-size_t mpack_node_copy_data(mpack_node_t node, char* buffer, size_t bufsize) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- mpack_assert(bufsize == 0 || buffer != NULL, "buffer is NULL for maximum of %i bytes", (int)bufsize);
-
- mpack_type_t type = node.data->type;
- if (type != mpack_type_str && type != mpack_type_bin
- #if MPACK_EXTENSIONS
- && type != mpack_type_ext
- #endif
- ) {
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
- }
-
- if (node.data->len > bufsize) {
- mpack_node_flag_error(node, mpack_error_too_big);
- return 0;
- }
-
- mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
- return (size_t)node.data->len;
-}
-
-size_t mpack_node_copy_utf8(mpack_node_t node, char* buffer, size_t bufsize) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- mpack_assert(bufsize == 0 || buffer != NULL, "buffer is NULL for maximum of %i bytes", (int)bufsize);
-
- mpack_type_t type = node.data->type;
- if (type != mpack_type_str) {
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
- }
-
- if (node.data->len > bufsize) {
- mpack_node_flag_error(node, mpack_error_too_big);
- return 0;
- }
-
- if (!mpack_utf8_check(mpack_node_data_unchecked(node), node.data->len)) {
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
- }
-
- mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
- return (size_t)node.data->len;
-}
-
-void mpack_node_copy_cstr(mpack_node_t node, char* buffer, size_t bufsize) {
-
- // we can't break here because the error isn't recoverable; we
- // have to add a null-terminator.
- mpack_assert(buffer != NULL, "buffer is NULL");
- mpack_assert(bufsize >= 1, "buffer size is zero; you must have room for at least a null-terminator");
-
- if (mpack_node_error(node) != mpack_ok) {
- buffer[0] = '\0';
- return;
- }
-
- if (node.data->type != mpack_type_str) {
- buffer[0] = '\0';
- mpack_node_flag_error(node, mpack_error_type);
- return;
- }
-
- if (node.data->len > bufsize - 1) {
- buffer[0] = '\0';
- mpack_node_flag_error(node, mpack_error_too_big);
- return;
- }
-
- if (!mpack_str_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
- buffer[0] = '\0';
- mpack_node_flag_error(node, mpack_error_type);
- return;
- }
-
- mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
- buffer[node.data->len] = '\0';
-}
-
-void mpack_node_copy_utf8_cstr(mpack_node_t node, char* buffer, size_t bufsize) {
-
- // we can't break here because the error isn't recoverable; we
- // have to add a null-terminator.
- mpack_assert(buffer != NULL, "buffer is NULL");
- mpack_assert(bufsize >= 1, "buffer size is zero; you must have room for at least a null-terminator");
-
- if (mpack_node_error(node) != mpack_ok) {
- buffer[0] = '\0';
- return;
- }
-
- if (node.data->type != mpack_type_str) {
- buffer[0] = '\0';
- mpack_node_flag_error(node, mpack_error_type);
- return;
- }
-
- if (node.data->len > bufsize - 1) {
- buffer[0] = '\0';
- mpack_node_flag_error(node, mpack_error_too_big);
- return;
- }
-
- if (!mpack_utf8_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
- buffer[0] = '\0';
- mpack_node_flag_error(node, mpack_error_type);
- return;
- }
-
- mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
- buffer[node.data->len] = '\0';
-}
-
-#ifdef MPACK_MALLOC
-char* mpack_node_data_alloc(mpack_node_t node, size_t maxlen) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- // make sure this is a valid data type
- mpack_type_t type = node.data->type;
- if (type != mpack_type_str && type != mpack_type_bin
- #if MPACK_EXTENSIONS
- && type != mpack_type_ext
- #endif
- ) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- if (node.data->len > maxlen) {
- mpack_node_flag_error(node, mpack_error_too_big);
- return NULL;
- }
-
- char* ret = (char*) MPACK_MALLOC((size_t)node.data->len);
- if (ret == NULL) {
- mpack_node_flag_error(node, mpack_error_memory);
- return NULL;
- }
-
- mpack_memcpy(ret, mpack_node_data_unchecked(node), node.data->len);
- return ret;
-}
-
-char* mpack_node_cstr_alloc(mpack_node_t node, size_t maxlen) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- // make sure maxlen makes sense
- if (maxlen < 1) {
- mpack_break("maxlen is zero; you must have room for at least a null-terminator");
- mpack_node_flag_error(node, mpack_error_bug);
- return NULL;
- }
-
- if (node.data->type != mpack_type_str) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- if (node.data->len > maxlen - 1) {
- mpack_node_flag_error(node, mpack_error_too_big);
- return NULL;
- }
-
- if (!mpack_str_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- char* ret = (char*) MPACK_MALLOC((size_t)(node.data->len + 1));
- if (ret == NULL) {
- mpack_node_flag_error(node, mpack_error_memory);
- return NULL;
- }
-
- mpack_memcpy(ret, mpack_node_data_unchecked(node), node.data->len);
- ret[node.data->len] = '\0';
- return ret;
-}
-
-char* mpack_node_utf8_cstr_alloc(mpack_node_t node, size_t maxlen) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- // make sure maxlen makes sense
- if (maxlen < 1) {
- mpack_break("maxlen is zero; you must have room for at least a null-terminator");
- mpack_node_flag_error(node, mpack_error_bug);
- return NULL;
- }
-
- if (node.data->type != mpack_type_str) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- if (node.data->len > maxlen - 1) {
- mpack_node_flag_error(node, mpack_error_too_big);
- return NULL;
- }
-
- if (!mpack_utf8_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- char* ret = (char*) MPACK_MALLOC((size_t)(node.data->len + 1));
- if (ret == NULL) {
- mpack_node_flag_error(node, mpack_error_memory);
- return NULL;
- }
-
- mpack_memcpy(ret, mpack_node_data_unchecked(node), node.data->len);
- ret[node.data->len] = '\0';
- return ret;
-}
-#endif
-
-
-/*
- * Compound Node Functions
- */
-
-static mpack_node_data_t* mpack_node_map_int_impl(mpack_node_t node, int64_t num) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- if (node.data->type != mpack_type_map) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- mpack_node_data_t* found = NULL;
-
- for (size_t i = 0; i < node.data->len; ++i) {
- mpack_node_data_t* key = mpack_node_child(node, i * 2);
-
- if ((key->type == mpack_type_int && key->value.i == num) ||
- (key->type == mpack_type_uint && num >= 0 && key->value.u == (uint64_t)num))
- {
- if (found) {
- mpack_node_flag_error(node, mpack_error_data);
- return NULL;
- }
- found = mpack_node_child(node, i * 2 + 1);
- }
- }
-
- if (found)
- return found;
-
- return NULL;
-}
-
-static mpack_node_data_t* mpack_node_map_uint_impl(mpack_node_t node, uint64_t num) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- if (node.data->type != mpack_type_map) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- mpack_node_data_t* found = NULL;
-
- for (size_t i = 0; i < node.data->len; ++i) {
- mpack_node_data_t* key = mpack_node_child(node, i * 2);
-
- if ((key->type == mpack_type_uint && key->value.u == num) ||
- (key->type == mpack_type_int && key->value.i >= 0 && (uint64_t)key->value.i == num))
- {
- if (found) {
- mpack_node_flag_error(node, mpack_error_data);
- return NULL;
- }
- found = mpack_node_child(node, i * 2 + 1);
- }
- }
-
- if (found)
- return found;
-
- return NULL;
-}
-
-static mpack_node_data_t* mpack_node_map_str_impl(mpack_node_t node, const char* str, size_t length) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- mpack_assert(length == 0 || str != NULL, "str of length %i is NULL", (int)length);
-
- if (node.data->type != mpack_type_map) {
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
- }
-
- mpack_tree_t* tree = node.tree;
- mpack_node_data_t* found = NULL;
-
- for (size_t i = 0; i < node.data->len; ++i) {
- mpack_node_data_t* key = mpack_node_child(node, i * 2);
-
- if (key->type == mpack_type_str && key->len == length &&
- mpack_memcmp(str, mpack_node_data_unchecked(mpack_node(tree, key)), length) == 0) {
- if (found) {
- mpack_node_flag_error(node, mpack_error_data);
- return NULL;
- }
- found = mpack_node_child(node, i * 2 + 1);
- }
- }
-
- if (found)
- return found;
-
- return NULL;
-}
-
-static mpack_node_t mpack_node_wrap_lookup(mpack_tree_t* tree, mpack_node_data_t* data) {
- if (!data) {
- if (tree->error == mpack_ok)
- mpack_tree_flag_error(tree, mpack_error_data);
- return mpack_tree_nil_node(tree);
- }
- return mpack_node(tree, data);
-}
-
-static mpack_node_t mpack_node_wrap_lookup_optional(mpack_tree_t* tree, mpack_node_data_t* data) {
- if (!data) {
- if (tree->error == mpack_ok)
- return mpack_tree_missing_node(tree);
- return mpack_tree_nil_node(tree);
- }
- return mpack_node(tree, data);
-}
-
-mpack_node_t mpack_node_map_int(mpack_node_t node, int64_t num) {
- return mpack_node_wrap_lookup(node.tree, mpack_node_map_int_impl(node, num));
-}
-
-mpack_node_t mpack_node_map_int_optional(mpack_node_t node, int64_t num) {
- return mpack_node_wrap_lookup_optional(node.tree, mpack_node_map_int_impl(node, num));
-}
-
-mpack_node_t mpack_node_map_uint(mpack_node_t node, uint64_t num) {
- return mpack_node_wrap_lookup(node.tree, mpack_node_map_uint_impl(node, num));
-}
-
-mpack_node_t mpack_node_map_uint_optional(mpack_node_t node, uint64_t num) {
- return mpack_node_wrap_lookup_optional(node.tree, mpack_node_map_uint_impl(node, num));
-}
-
-mpack_node_t mpack_node_map_str(mpack_node_t node, const char* str, size_t length) {
- return mpack_node_wrap_lookup(node.tree, mpack_node_map_str_impl(node, str, length));
-}
-
-mpack_node_t mpack_node_map_str_optional(mpack_node_t node, const char* str, size_t length) {
- return mpack_node_wrap_lookup_optional(node.tree, mpack_node_map_str_impl(node, str, length));
-}
-
-mpack_node_t mpack_node_map_cstr(mpack_node_t node, const char* cstr) {
- mpack_assert(cstr != NULL, "cstr is NULL");
- return mpack_node_map_str(node, cstr, mpack_strlen(cstr));
-}
-
-mpack_node_t mpack_node_map_cstr_optional(mpack_node_t node, const char* cstr) {
- mpack_assert(cstr != NULL, "cstr is NULL");
- return mpack_node_map_str_optional(node, cstr, mpack_strlen(cstr));
-}
-
-bool mpack_node_map_contains_int(mpack_node_t node, int64_t num) {
- return mpack_node_map_int_impl(node, num) != NULL;
-}
-
-bool mpack_node_map_contains_uint(mpack_node_t node, uint64_t num) {
- return mpack_node_map_uint_impl(node, num) != NULL;
-}
-
-bool mpack_node_map_contains_str(mpack_node_t node, const char* str, size_t length) {
- return mpack_node_map_str_impl(node, str, length) != NULL;
-}
-
-bool mpack_node_map_contains_cstr(mpack_node_t node, const char* cstr) {
- mpack_assert(cstr != NULL, "cstr is NULL");
- return mpack_node_map_contains_str(node, cstr, mpack_strlen(cstr));
-}
-
-size_t mpack_node_enum_optional(mpack_node_t node, const char* strings[], size_t count) {
- if (mpack_node_error(node) != mpack_ok)
- return count;
-
- // the value is only recognized if it is a string
- if (mpack_node_type(node) != mpack_type_str)
- return count;
-
- // fetch the string
- const char* key = mpack_node_str(node);
- size_t keylen = mpack_node_strlen(node);
- mpack_assert(mpack_node_error(node) == mpack_ok, "these should not fail");
-
- // find what key it matches
- for (size_t i = 0; i < count; ++i) {
- const char* other = strings[i];
- size_t otherlen = mpack_strlen(other);
- if (keylen == otherlen && mpack_memcmp(key, other, keylen) == 0)
- return i;
- }
-
- // no matches
- return count;
-}
-
-size_t mpack_node_enum(mpack_node_t node, const char* strings[], size_t count) {
- size_t value = mpack_node_enum_optional(node, strings, count);
- if (value == count)
- mpack_node_flag_error(node, mpack_error_type);
- return value;
-}
-
-mpack_type_t mpack_node_type(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return mpack_type_nil;
- return node.data->type;
-}
-
-bool mpack_node_is_nil(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok) {
- // All nodes are treated as nil nodes when we are in error.
- return true;
- }
- return node.data->type == mpack_type_nil;
-}
-
-bool mpack_node_is_missing(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok) {
- // errors still return nil nodes, not missing nodes.
- return false;
- }
- return node.data->type == mpack_type_missing;
-}
-
-void mpack_node_nil(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return;
- if (node.data->type != mpack_type_nil)
- mpack_node_flag_error(node, mpack_error_type);
-}
-
-void mpack_node_missing(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return;
- if (node.data->type != mpack_type_missing)
- mpack_node_flag_error(node, mpack_error_type);
-}
-
-bool mpack_node_bool(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return false;
-
- if (node.data->type == mpack_type_bool)
- return node.data->value.b;
-
- mpack_node_flag_error(node, mpack_error_type);
- return false;
-}
-
-void mpack_node_true(mpack_node_t node) {
- if (mpack_node_bool(node) != true)
- mpack_node_flag_error(node, mpack_error_type);
-}
-
-void mpack_node_false(mpack_node_t node) {
- if (mpack_node_bool(node) != false)
- mpack_node_flag_error(node, mpack_error_type);
-}
-
-uint8_t mpack_node_u8(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= UINT8_MAX)
- return (uint8_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= 0 && node.data->value.i <= UINT8_MAX)
- return (uint8_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-int8_t mpack_node_i8(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= INT8_MAX)
- return (int8_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= INT8_MIN && node.data->value.i <= INT8_MAX)
- return (int8_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-uint16_t mpack_node_u16(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= UINT16_MAX)
- return (uint16_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= 0 && node.data->value.i <= UINT16_MAX)
- return (uint16_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-int16_t mpack_node_i16(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= INT16_MAX)
- return (int16_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= INT16_MIN && node.data->value.i <= INT16_MAX)
- return (int16_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-uint32_t mpack_node_u32(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= UINT32_MAX)
- return (uint32_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= 0 && node.data->value.i <= UINT32_MAX)
- return (uint32_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-int32_t mpack_node_i32(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= INT32_MAX)
- return (int32_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= INT32_MIN && node.data->value.i <= INT32_MAX)
- return (int32_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-uint64_t mpack_node_u64(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- return node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- if (node.data->value.i >= 0)
- return (uint64_t)node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-int64_t mpack_node_i64(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_uint) {
- if (node.data->value.u <= (uint64_t)INT64_MAX)
- return (int64_t)node.data->value.u;
- } else if (node.data->type == mpack_type_int) {
- return node.data->value.i;
- }
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-unsigned int mpack_node_uint(mpack_node_t node) {
-
- // This should be true at compile-time, so this just wraps the 32-bit function.
- if (sizeof(unsigned int) == 4)
- return (unsigned int)mpack_node_u32(node);
-
- // Otherwise we use u64 and check the range.
- uint64_t val = mpack_node_u64(node);
- if (val <= UINT_MAX)
- return (unsigned int)val;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-int mpack_node_int(mpack_node_t node) {
-
- // This should be true at compile-time, so this just wraps the 32-bit function.
- if (sizeof(int) == 4)
- return (int)mpack_node_i32(node);
-
- // Otherwise we use i64 and check the range.
- int64_t val = mpack_node_i64(node);
- if (val >= INT_MIN && val <= INT_MAX)
- return (int)val;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-float mpack_node_float(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0.0f;
-
- if (node.data->type == mpack_type_uint)
- return (float)node.data->value.u;
- else if (node.data->type == mpack_type_int)
- return (float)node.data->value.i;
- else if (node.data->type == mpack_type_float)
- return node.data->value.f;
- else if (node.data->type == mpack_type_double)
- return (float)node.data->value.d;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0.0f;
-}
-
-double mpack_node_double(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0.0;
-
- if (node.data->type == mpack_type_uint)
- return (double)node.data->value.u;
- else if (node.data->type == mpack_type_int)
- return (double)node.data->value.i;
- else if (node.data->type == mpack_type_float)
- return (double)node.data->value.f;
- else if (node.data->type == mpack_type_double)
- return node.data->value.d;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0.0;
-}
-
-float mpack_node_float_strict(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0.0f;
-
- if (node.data->type == mpack_type_float)
- return node.data->value.f;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0.0f;
-}
-
-double mpack_node_double_strict(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0.0;
-
- if (node.data->type == mpack_type_float)
- return (double)node.data->value.f;
- else if (node.data->type == mpack_type_double)
- return node.data->value.d;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0.0;
-}
-
-#if MPACK_EXTENSIONS
-int8_t mpack_node_exttype(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_ext)
- return mpack_node_exttype_unchecked(node);
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-#endif
-
-uint32_t mpack_node_data_len(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- mpack_type_t type = node.data->type;
- if (type == mpack_type_str || type == mpack_type_bin
- #if MPACK_EXTENSIONS
- || type == mpack_type_ext
- #endif
- )
- return (uint32_t)node.data->len;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-size_t mpack_node_strlen(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_str)
- return (size_t)node.data->len;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-const char* mpack_node_str(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- mpack_type_t type = node.data->type;
- if (type == mpack_type_str)
- return mpack_node_data_unchecked(node);
-
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
-}
-
-const char* mpack_node_data(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- mpack_type_t type = node.data->type;
- if (type == mpack_type_str || type == mpack_type_bin
- #if MPACK_EXTENSIONS
- || type == mpack_type_ext
- #endif
- )
- return mpack_node_data_unchecked(node);
-
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
-}
-
-const char* mpack_node_bin_data(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return NULL;
-
- if (node.data->type == mpack_type_bin)
- return mpack_node_data_unchecked(node);
-
- mpack_node_flag_error(node, mpack_error_type);
- return NULL;
-}
-
-size_t mpack_node_bin_size(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type == mpack_type_bin)
- return (size_t)node.data->len;
-
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
-}
-
-size_t mpack_node_array_length(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type != mpack_type_array) {
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
- }
-
- return (size_t)node.data->len;
-}
-
-mpack_node_t mpack_node_array_at(mpack_node_t node, size_t index) {
- if (mpack_node_error(node) != mpack_ok)
- return mpack_tree_nil_node(node.tree);
-
- if (node.data->type != mpack_type_array) {
- mpack_node_flag_error(node, mpack_error_type);
- return mpack_tree_nil_node(node.tree);
- }
-
- if (index >= node.data->len) {
- mpack_node_flag_error(node, mpack_error_data);
- return mpack_tree_nil_node(node.tree);
- }
-
- return mpack_node(node.tree, mpack_node_child(node, index));
-}
-
-size_t mpack_node_map_count(mpack_node_t node) {
- if (mpack_node_error(node) != mpack_ok)
- return 0;
-
- if (node.data->type != mpack_type_map) {
- mpack_node_flag_error(node, mpack_error_type);
- return 0;
- }
-
- return node.data->len;
-}
-
-// internal node map lookup
-static mpack_node_t mpack_node_map_at(mpack_node_t node, size_t index, size_t offset) {
- if (mpack_node_error(node) != mpack_ok)
- return mpack_tree_nil_node(node.tree);
-
- if (node.data->type != mpack_type_map) {
- mpack_node_flag_error(node, mpack_error_type);
- return mpack_tree_nil_node(node.tree);
- }
-
- if (index >= node.data->len) {
- mpack_node_flag_error(node, mpack_error_data);
- return mpack_tree_nil_node(node.tree);
- }
-
- return mpack_node(node.tree, mpack_node_child(node, index * 2 + offset));
-}
-
-mpack_node_t mpack_node_map_key_at(mpack_node_t node, size_t index) {
- return mpack_node_map_at(node, index, 0);
-}
-
-mpack_node_t mpack_node_map_value_at(mpack_node_t node, size_t index) {
- return mpack_node_map_at(node, index, 1);
-}
-
-#endif
diff --git a/src/lib/mpmalloc.cc b/src/lib/mpmalloc.cc
deleted file mode 100644
index 2483a3a..0000000
--- a/src/lib/mpmalloc.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <stdlib.h>
-#include "driver/stdout.h"
-#include "lib/mpmalloc.h"
-
-void* mpcalloc(size_t nmemb, size_t size)
-{
- void* ret = calloc(nmemb, size);
-#ifdef ADDR_20BIT
- kout << "calloc:" << dec << (uint32_t)nmemb << "x" << (uint32_t)size << "@" << ret << endl;
-#else
- kout << "calloc:" << dec << nmemb << "x" << size << "@" << ret << endl;
-#endif
- return ret;
-}
-
-void* mpmalloc(size_t size)
-{
- void* ret = malloc(size);
-#ifdef ADDR_20BIT
- kout << "malloc:" << dec << (uint32_t)size << "@" << ret << endl;
-#else
- kout << "malloc:" << dec << size << "@" << ret << endl;
-#endif
- return ret;
-}
-
-void* mprealloc(void* addr, size_t size)
-{
- void* ret = realloc(addr, size);
-#ifdef ADDR_20BIT
- kout << "realloc:" << addr << ":" << dec << (uint32_t)size << "@" << ret << endl;
-#else
- kout << "realloc:" << addr << ":" << dec << size << "@" << ret << endl;
-#endif
- return ret;
-}
-
-void mpfree(void* addr)
-{
- kout << "free:" << addr << endl;
- free(addr);
-}
diff --git a/src/lib/nanopb/pb_common.cc b/src/lib/nanopb/pb_common.cc
deleted file mode 100644
index 4fb7186..0000000
--- a/src/lib/nanopb/pb_common.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
- *
- * 2014 Petteri Aimonen <jpa@kapsi.fi>
- */
-
-#include "pb_common.h"
-
-bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct)
-{
- iter->start = fields;
- iter->pos = fields;
- iter->required_field_index = 0;
- iter->dest_struct = dest_struct;
- iter->pData = (char*)dest_struct + iter->pos->data_offset;
- iter->pSize = (char*)iter->pData + iter->pos->size_offset;
-
- return (iter->pos->tag != 0);
-}
-
-bool pb_field_iter_next(pb_field_iter_t *iter)
-{
- const pb_field_t *prev_field = iter->pos;
-
- if (prev_field->tag == 0)
- {
- /* Handle empty message types, where the first field is already the terminator.
- * In other cases, the iter->pos never points to the terminator. */
- return false;
- }
-
- iter->pos++;
-
- if (iter->pos->tag == 0)
- {
- /* Wrapped back to beginning, reinitialize */
- (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct);
- return false;
- }
- else
- {
- /* Increment the pointers based on previous field size */
- size_t prev_size = prev_field->data_size;
-
- if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF &&
- PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF &&
- iter->pos->data_offset == PB_SIZE_MAX)
- {
- /* Don't advance pointers inside unions */
- return true;
- }
- else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC &&
- PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED)
- {
- /* In static arrays, the data_size tells the size of a single entry and
- * array_size is the number of entries */
- prev_size *= prev_field->array_size;
- }
- else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER)
- {
- /* Pointer fields always have a constant size in the main structure.
- * The data_size only applies to the dynamically allocated area. */
- prev_size = sizeof(void*);
- }
-
- if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED)
- {
- /* Count the required fields, in order to check their presence in the
- * decoder. */
- iter->required_field_index++;
- }
-
- iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset;
- iter->pSize = (char*)iter->pData + iter->pos->size_offset;
- return true;
- }
-}
-
-bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
-{
- const pb_field_t *start = iter->pos;
-
- do {
- if (iter->pos->tag == tag &&
- PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION)
- {
- /* Found the wanted field */
- return true;
- }
-
- (void)pb_field_iter_next(iter);
- } while (iter->pos != start);
-
- /* Searched all the way back to start, and found nothing. */
- return false;
-}
-
-
diff --git a/src/lib/nanopb/pb_decode.cc b/src/lib/nanopb/pb_decode.cc
deleted file mode 100644
index d08259c..0000000
--- a/src/lib/nanopb/pb_decode.cc
+++ /dev/null
@@ -1,1528 +0,0 @@
-/* pb_decode.c -- decode a protobuf using minimal resources
- *
- * 2011 Petteri Aimonen <jpa@kapsi.fi>
- */
-
-/* Use the GCC warn_unused_result attribute to check that all return values
- * are propagated correctly. On other compilers and gcc before 3.4.0 just
- * ignore the annotation.
- */
-#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
- #define checkreturn
-#else
- #define checkreturn __attribute__((warn_unused_result))
-#endif
-
-#include "pb.h"
-#include "pb_decode.h"
-#include "pb_common.h"
-
-/**************************************
- * Declarations internal to this file *
- **************************************/
-
-typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn;
-
-static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
-static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
-static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);
-static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
-static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static bool checkreturn find_extension_field(pb_field_iter_t *iter);
-static void pb_field_set_to_default(pb_field_iter_t *iter);
-static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);
-static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof);
-static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_skip_varint(pb_istream_t *stream);
-static bool checkreturn pb_skip_string(pb_istream_t *stream);
-
-#ifdef PB_ENABLE_MALLOC
-static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);
-static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter);
-static void pb_release_single_field(const pb_field_iter_t *iter);
-#endif
-
-#ifdef PB_WITHOUT_64BIT
-#define pb_int64_t int32_t
-#define pb_uint64_t uint32_t
-#else
-#define pb_int64_t int64_t
-#define pb_uint64_t uint64_t
-#endif
-
-/* --- Function pointers to field decoders ---
- * Order in the array must match pb_action_t LTYPE numbering.
- */
-static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
- &pb_dec_varint,
- &pb_dec_uvarint,
- &pb_dec_svarint,
- &pb_dec_fixed32,
- &pb_dec_fixed64,
-
- &pb_dec_bytes,
- &pb_dec_string,
- &pb_dec_submessage,
- NULL, /* extensions */
- &pb_dec_fixed_length_bytes
-};
-
-/*******************************
- * pb_istream_t implementation *
- *******************************/
-
-static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
-{
- size_t i;
- const pb_byte_t *source = (const pb_byte_t*)stream->state;
- stream->state = (pb_byte_t*)stream->state + count;
-
- if (buf != NULL)
- {
- for (i = 0; i < count; i++)
- buf[i] = source[i];
- }
-
- return true;
-}
-
-bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
-{
-#ifndef PB_BUFFER_ONLY
- if (buf == NULL && stream->callback != buf_read)
- {
- /* Skip input bytes */
- pb_byte_t tmp[16];
- while (count > 16)
- {
- if (!pb_read(stream, tmp, 16))
- return false;
-
- count -= 16;
- }
-
- return pb_read(stream, tmp, count);
- }
-#endif
-
- if (stream->bytes_left < count)
- PB_RETURN_ERROR(stream, "end-of-stream");
-
-#ifndef PB_BUFFER_ONLY
- if (!stream->callback(stream, buf, count))
- PB_RETURN_ERROR(stream, "io error");
-#else
- if (!buf_read(stream, buf, count))
- return false;
-#endif
-
- stream->bytes_left -= count;
- return true;
-}
-
-/* Read a single byte from input stream. buf may not be NULL.
- * This is an optimization for the varint decoding. */
-static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf)
-{
- if (stream->bytes_left == 0)
- PB_RETURN_ERROR(stream, "end-of-stream");
-
-#ifndef PB_BUFFER_ONLY
- if (!stream->callback(stream, buf, 1))
- PB_RETURN_ERROR(stream, "io error");
-#else
- *buf = *(const pb_byte_t*)stream->state;
- stream->state = (pb_byte_t*)stream->state + 1;
-#endif
-
- stream->bytes_left--;
-
- return true;
-}
-
-pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
-{
- pb_istream_t stream;
- /* Cast away the const from buf without a compiler error. We are
- * careful to use it only in a const manner in the callbacks.
- */
- union {
- void *state;
- const void *c_state;
- } state;
-#ifdef PB_BUFFER_ONLY
- stream.callback = NULL;
-#else
- stream.callback = &buf_read;
-#endif
- state.c_state = buf;
- stream.state = state.state;
- stream.bytes_left = bufsize;
-#ifndef PB_NO_ERRMSG
- stream.errmsg = NULL;
-#endif
- return stream;
-}
-
-/********************
- * Helper functions *
- ********************/
-
-static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof)
-{
- pb_byte_t byte;
- uint32_t result;
-
- if (!pb_readbyte(stream, &byte))
- {
- if (stream->bytes_left == 0)
- {
- if (eof)
- {
- *eof = true;
- }
- }
-
- return false;
- }
-
- if ((byte & 0x80) == 0)
- {
- /* Quick case, 1 byte value */
- result = byte;
- }
- else
- {
- /* Multibyte case */
- uint_fast8_t bitpos = 7;
- result = byte & 0x7F;
-
- do
- {
- if (!pb_readbyte(stream, &byte))
- return false;
-
- if (bitpos >= 32)
- {
- /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */
- uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;
-
- if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension))
- {
- PB_RETURN_ERROR(stream, "varint overflow");
- }
- }
- else
- {
- result |= (uint32_t)(byte & 0x7F) << bitpos;
- }
- bitpos = (uint_fast8_t)(bitpos + 7);
- } while (byte & 0x80);
-
- if (bitpos == 35 && (byte & 0x70) != 0)
- {
- /* The last byte was at bitpos=28, so only bottom 4 bits fit. */
- PB_RETURN_ERROR(stream, "varint overflow");
- }
- }
-
- *dest = result;
- return true;
-}
-
-bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
-{
- return pb_decode_varint32_eof(stream, dest, NULL);
-}
-
-#ifndef PB_WITHOUT_64BIT
-bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
-{
- pb_byte_t byte;
- uint_fast8_t bitpos = 0;
- uint64_t result = 0;
-
- do
- {
- if (bitpos >= 64)
- PB_RETURN_ERROR(stream, "varint overflow");
-
- if (!pb_readbyte(stream, &byte))
- return false;
-
- result |= (uint64_t)(byte & 0x7F) << bitpos;
- bitpos = (uint_fast8_t)(bitpos + 7);
- } while (byte & 0x80);
-
- *dest = result;
- return true;
-}
-#endif
-
-bool checkreturn pb_skip_varint(pb_istream_t *stream)
-{
- pb_byte_t byte;
- do
- {
- if (!pb_read(stream, &byte, 1))
- return false;
- } while (byte & 0x80);
- return true;
-}
-
-bool checkreturn pb_skip_string(pb_istream_t *stream)
-{
- uint32_t length;
- if (!pb_decode_varint32(stream, &length))
- return false;
-
- return pb_read(stream, NULL, length);
-}
-
-bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof)
-{
- uint32_t temp;
- *eof = false;
- *wire_type = (pb_wire_type_t) 0;
- *tag = 0;
-
- if (!pb_decode_varint32_eof(stream, &temp, eof))
- {
- return false;
- }
-
- if (temp == 0)
- {
- *eof = true; /* Special feature: allow 0-terminated messages. */
- return false;
- }
-
- *tag = temp >> 3;
- *wire_type = (pb_wire_type_t)(temp & 7);
- return true;
-}
-
-bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type)
-{
- switch (wire_type)
- {
- case PB_WT_VARINT: return pb_skip_varint(stream);
- case PB_WT_64BIT: return pb_read(stream, NULL, 8);
- case PB_WT_STRING: return pb_skip_string(stream);
- case PB_WT_32BIT: return pb_read(stream, NULL, 4);
- default: PB_RETURN_ERROR(stream, "invalid wire_type");
- }
-}
-
-/* Read a raw value to buffer, for the purpose of passing it to callback as
- * a substream. Size is maximum size on call, and actual size on return.
- */
-static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size)
-{
- size_t max_size = *size;
- switch (wire_type)
- {
- case PB_WT_VARINT:
- *size = 0;
- do
- {
- (*size)++;
- if (*size > max_size) return false;
- if (!pb_read(stream, buf, 1)) return false;
- } while (*buf++ & 0x80);
- return true;
-
- case PB_WT_64BIT:
- *size = 8;
- return pb_read(stream, buf, 8);
-
- case PB_WT_32BIT:
- *size = 4;
- return pb_read(stream, buf, 4);
-
- case PB_WT_STRING:
- /* Calling read_raw_value with a PB_WT_STRING is an error.
- * Explicitly handle this case and fallthrough to default to avoid
- * compiler warnings.
- */
-
- default: PB_RETURN_ERROR(stream, "invalid wire_type");
- }
-}
-
-/* Decode string length from stream and return a substream with limited length.
- * Remember to close the substream using pb_close_string_substream().
- */
-bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream)
-{
- uint32_t size;
- if (!pb_decode_varint32(stream, &size))
- return false;
-
- *substream = *stream;
- if (substream->bytes_left < size)
- PB_RETURN_ERROR(stream, "parent stream too short");
-
- substream->bytes_left = size;
- stream->bytes_left -= size;
- return true;
-}
-
-bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
-{
- if (substream->bytes_left) {
- if (!pb_read(substream, NULL, substream->bytes_left))
- return false;
- }
-
- stream->state = substream->state;
-
-#ifndef PB_NO_ERRMSG
- stream->errmsg = substream->errmsg;
-#endif
- return true;
-}
-
-/*************************
- * Decode a single field *
- *************************/
-
-static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
-{
- pb_type_t type;
- pb_decoder_t func;
-
- type = iter->pos->type;
- func = PB_DECODERS[PB_LTYPE(type)];
-
- switch (PB_HTYPE(type))
- {
- case PB_HTYPE_REQUIRED:
- return func(stream, iter->pos, iter->pData);
-
- case PB_HTYPE_OPTIONAL:
- if (iter->pSize != iter->pData)
- *(bool*)iter->pSize = true;
- return func(stream, iter->pos, iter->pData);
-
- case PB_HTYPE_REPEATED:
- if (wire_type == PB_WT_STRING
- && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
- {
- /* Packed array */
- bool status = true;
- pb_size_t *size = (pb_size_t*)iter->pSize;
-
- pb_istream_t substream;
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- while (substream.bytes_left > 0 && *size < iter->pos->array_size)
- {
- void *pItem = (char*)iter->pData + iter->pos->data_size * (*size);
- if (!func(&substream, iter->pos, pItem))
- {
- status = false;
- break;
- }
- (*size)++;
- }
-
- if (substream.bytes_left != 0)
- PB_RETURN_ERROR(stream, "array overflow");
- if (!pb_close_string_substream(stream, &substream))
- return false;
-
- return status;
- }
- else
- {
- /* Repeated field */
- pb_size_t *size = (pb_size_t*)iter->pSize;
- char *pItem = (char*)iter->pData + iter->pos->data_size * (*size);
-
- if ((*size)++ >= iter->pos->array_size)
- PB_RETURN_ERROR(stream, "array overflow");
-
- return func(stream, iter->pos, pItem);
- }
-
- case PB_HTYPE_ONEOF:
- *(pb_size_t*)iter->pSize = iter->pos->tag;
- if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
- {
- /* We memset to zero so that any callbacks are set to NULL.
- * Then set any default values. */
- memset(iter->pData, 0, iter->pos->data_size);
- pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData);
- }
- return func(stream, iter->pos, iter->pData);
-
- default:
- PB_RETURN_ERROR(stream, "invalid field type");
- }
-}
-
-#ifdef PB_ENABLE_MALLOC
-/* Allocate storage for the field and store the pointer at iter->pData.
- * array_size is the number of entries to reserve in an array.
- * Zero size is not allowed, use pb_free() for releasing.
- */
-static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size)
-{
- void *ptr = *(void**)pData;
-
- if (data_size == 0 || array_size == 0)
- PB_RETURN_ERROR(stream, "invalid size");
-
- /* Check for multiplication overflows.
- * This code avoids the costly division if the sizes are small enough.
- * Multiplication is safe as long as only half of bits are set
- * in either multiplicand.
- */
- {
- const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
- if (data_size >= check_limit || array_size >= check_limit)
- {
- const size_t size_max = (size_t)-1;
- if (size_max / array_size < data_size)
- {
- PB_RETURN_ERROR(stream, "size too large");
- }
- }
- }
-
- /* Allocate new or expand previous allocation */
- /* Note: on failure the old pointer will remain in the structure,
- * the message must be freed by caller also on error return. */
- ptr = pb_realloc(ptr, array_size * data_size);
- if (ptr == NULL)
- PB_RETURN_ERROR(stream, "realloc failed");
-
- *(void**)pData = ptr;
- return true;
-}
-
-/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */
-static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter)
-{
- if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING ||
- PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES)
- {
- *(void**)pItem = NULL;
- }
- else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
- {
- /* We memset to zero so that any callbacks are set to NULL.
- * Then set any default values. */
- memset(pItem, 0, iter->pos->data_size);
- pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem);
- }
-}
-#endif
-
-static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
-{
-#ifndef PB_ENABLE_MALLOC
- PB_UNUSED(wire_type);
- PB_UNUSED(iter);
- PB_RETURN_ERROR(stream, "no malloc support");
-#else
- pb_type_t type;
- pb_decoder_t func;
-
- type = iter->pos->type;
- func = PB_DECODERS[PB_LTYPE(type)];
-
- switch (PB_HTYPE(type))
- {
- case PB_HTYPE_REQUIRED:
- case PB_HTYPE_OPTIONAL:
- case PB_HTYPE_ONEOF:
- if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE &&
- *(void**)iter->pData != NULL)
- {
- /* Duplicate field, have to release the old allocation first. */
- pb_release_single_field(iter);
- }
-
- if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
- {
- *(pb_size_t*)iter->pSize = iter->pos->tag;
- }
-
- if (PB_LTYPE(type) == PB_LTYPE_STRING ||
- PB_LTYPE(type) == PB_LTYPE_BYTES)
- {
- return func(stream, iter->pos, iter->pData);
- }
- else
- {
- if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1))
- return false;
-
- initialize_pointer_field(*(void**)iter->pData, iter);
- return func(stream, iter->pos, *(void**)iter->pData);
- }
-
- case PB_HTYPE_REPEATED:
- if (wire_type == PB_WT_STRING
- && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
- {
- /* Packed array, multiple items come in at once. */
- bool status = true;
- pb_size_t *size = (pb_size_t*)iter->pSize;
- size_t allocated_size = *size;
- void *pItem;
- pb_istream_t substream;
-
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- while (substream.bytes_left)
- {
- if ((size_t)*size + 1 > allocated_size)
- {
- /* Allocate more storage. This tries to guess the
- * number of remaining entries. Round the division
- * upwards. */
- allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1;
-
- if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size))
- {
- status = false;
- break;
- }
- }
-
- /* Decode the array entry */
- pItem = *(char**)iter->pData + iter->pos->data_size * (*size);
- initialize_pointer_field(pItem, iter);
- if (!func(&substream, iter->pos, pItem))
- {
- status = false;
- break;
- }
-
- if (*size == PB_SIZE_MAX)
- {
-#ifndef PB_NO_ERRMSG
- stream->errmsg = "too many array entries";
-#endif
- status = false;
- break;
- }
-
- (*size)++;
- }
- if (!pb_close_string_substream(stream, &substream))
- return false;
-
- return status;
- }
- else
- {
- /* Normal repeated field, i.e. only one item at a time. */
- pb_size_t *size = (pb_size_t*)iter->pSize;
- void *pItem;
-
- if (*size == PB_SIZE_MAX)
- PB_RETURN_ERROR(stream, "too many array entries");
-
- (*size)++;
- if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
- return false;
-
- pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1);
- initialize_pointer_field(pItem, iter);
- return func(stream, iter->pos, pItem);
- }
-
- default:
- PB_RETURN_ERROR(stream, "invalid field type");
- }
-#endif
-}
-
-static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
-{
- pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
-#ifdef PB_OLD_CALLBACK_STYLE
- void *arg;
-#else
- void **arg;
-#endif
-
- if (pCallback == NULL || pCallback->funcs.decode == NULL)
- return pb_skip_field(stream, wire_type);
-
-#ifdef PB_OLD_CALLBACK_STYLE
- arg = pCallback->arg;
-#else
- arg = &(pCallback->arg);
-#endif
-
- if (wire_type == PB_WT_STRING)
- {
- pb_istream_t substream;
-
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- do
- {
- if (!pCallback->funcs.decode(&substream, iter->pos, arg))
- PB_RETURN_ERROR(stream, "callback failed");
- } while (substream.bytes_left);
-
- if (!pb_close_string_substream(stream, &substream))
- return false;
-
- return true;
- }
- else
- {
- /* Copy the single scalar value to stack.
- * This is required so that we can limit the stream length,
- * which in turn allows to use same callback for packed and
- * not-packed fields. */
- pb_istream_t substream;
- pb_byte_t buffer[10];
- size_t size = sizeof(buffer);
-
- if (!read_raw_value(stream, wire_type, buffer, &size))
- return false;
- substream = pb_istream_from_buffer(buffer, size);
-
- return pCallback->funcs.decode(&substream, iter->pos, arg);
- }
-}
-
-static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
-{
-#ifdef PB_ENABLE_MALLOC
- /* When decoding an oneof field, check if there is old data that must be
- * released first. */
- if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF)
- {
- if (!pb_release_union_field(stream, iter))
- return false;
- }
-#endif
-
- switch (PB_ATYPE(iter->pos->type))
- {
- case PB_ATYPE_STATIC:
- return decode_static_field(stream, wire_type, iter);
-
- case PB_ATYPE_POINTER:
- return decode_pointer_field(stream, wire_type, iter);
-
- case PB_ATYPE_CALLBACK:
- return decode_callback_field(stream, wire_type, iter);
-
- default:
- PB_RETURN_ERROR(stream, "invalid field type");
- }
-}
-
-static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension)
-{
- /* Fake a field iterator for the extension field.
- * It is not actually safe to advance this iterator, but decode_field
- * will not even try to. */
- const pb_field_t *field = (const pb_field_t*)extension->type->arg;
- (void)pb_field_iter_begin(iter, field, extension->dest);
- iter->pData = extension->dest;
- iter->pSize = &extension->found;
-
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
- {
- /* For pointer extensions, the pointer is stored directly
- * in the extension structure. This avoids having an extra
- * indirection. */
- iter->pData = &extension->dest;
- }
-}
-
-/* Default handler for extension fields. Expects a pb_field_t structure
- * in extension->type->arg. */
-static bool checkreturn default_extension_decoder(pb_istream_t *stream,
- pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type)
-{
- const pb_field_t *field = (const pb_field_t*)extension->type->arg;
- pb_field_iter_t iter;
-
- if (field->tag != tag)
- return true;
-
- iter_from_extension(&iter, extension);
- extension->found = true;
- return decode_field(stream, wire_type, &iter);
-}
-
-/* Try to decode an unknown field as an extension field. Tries each extension
- * decoder in turn, until one of them handles the field or loop ends. */
-static bool checkreturn decode_extension(pb_istream_t *stream,
- uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter)
-{
- pb_extension_t *extension = *(pb_extension_t* const *)iter->pData;
- size_t pos = stream->bytes_left;
-
- while (extension != NULL && pos == stream->bytes_left)
- {
- bool status;
- if (extension->type->decode)
- status = extension->type->decode(stream, extension, tag, wire_type);
- else
- status = default_extension_decoder(stream, extension, tag, wire_type);
-
- if (!status)
- return false;
-
- extension = extension->next;
- }
-
- return true;
-}
-
-/* Step through the iterator until an extension field is found or until all
- * entries have been checked. There can be only one extension field per
- * message. Returns false if no extension field is found. */
-static bool checkreturn find_extension_field(pb_field_iter_t *iter)
-{
- const pb_field_t *start = iter->pos;
-
- do {
- if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION)
- return true;
- (void)pb_field_iter_next(iter);
- } while (iter->pos != start);
-
- return false;
-}
-
-/* Initialize message fields to default values, recursively */
-static void pb_field_set_to_default(pb_field_iter_t *iter)
-{
- pb_type_t type;
- type = iter->pos->type;
-
- if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
- {
- pb_extension_t *ext = *(pb_extension_t* const *)iter->pData;
- while (ext != NULL)
- {
- pb_field_iter_t ext_iter;
- ext->found = false;
- iter_from_extension(&ext_iter, ext);
- pb_field_set_to_default(&ext_iter);
- ext = ext->next;
- }
- }
- else if (PB_ATYPE(type) == PB_ATYPE_STATIC)
- {
- bool init_data = true;
- if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData)
- {
- /* Set has_field to false. Still initialize the optional field
- * itself also. */
- *(bool*)iter->pSize = false;
- }
- else if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
- PB_HTYPE(type) == PB_HTYPE_ONEOF)
- {
- /* REPEATED: Set array count to 0, no need to initialize contents.
- ONEOF: Set which_field to 0. */
- *(pb_size_t*)iter->pSize = 0;
- init_data = false;
- }
-
- if (init_data)
- {
- if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
- {
- /* Initialize submessage to defaults */
- pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData);
- }
- else if (iter->pos->ptr != NULL)
- {
- /* Initialize to default value */
- memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size);
- }
- else
- {
- /* Initialize to zeros */
- memset(iter->pData, 0, iter->pos->data_size);
- }
- }
- }
- else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
- {
- /* Initialize the pointer to NULL. */
- *(void**)iter->pData = NULL;
-
- /* Initialize array count to 0. */
- if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
- PB_HTYPE(type) == PB_HTYPE_ONEOF)
- {
- *(pb_size_t*)iter->pSize = 0;
- }
- }
- else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
- {
- /* Don't overwrite callback */
- }
-}
-
-static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct)
-{
- pb_field_iter_t iter;
-
- if (!pb_field_iter_begin(&iter, fields, dest_struct))
- return; /* Empty message type */
-
- do
- {
- pb_field_set_to_default(&iter);
- } while (pb_field_iter_next(&iter));
-}
-
-/*********************
- * Decode all fields *
- *********************/
-
-bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
- uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0};
- const uint32_t allbits = ~(uint32_t)0;
- uint32_t extension_range_start = 0;
- pb_field_iter_t iter;
-
- /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed
- * count field. This can only handle _one_ repeated fixed count field that
- * is unpacked and unordered among other (non repeated fixed count) fields.
- */
- const pb_field_t *fixed_count_field = NULL;
- pb_size_t fixed_count_size = 0;
-
- /* Return value ignored, as empty message types will be correctly handled by
- * pb_field_iter_find() anyway. */
- (void)pb_field_iter_begin(&iter, fields, dest_struct);
-
- while (stream->bytes_left)
- {
- uint32_t tag;
- pb_wire_type_t wire_type;
- bool eof;
-
- if (!pb_decode_tag(stream, &wire_type, &tag, &eof))
- {
- if (eof)
- break;
- else
- return false;
- }
-
- if (!pb_field_iter_find(&iter, tag))
- {
- /* No match found, check if it matches an extension. */
- if (tag >= extension_range_start)
- {
- if (!find_extension_field(&iter))
- extension_range_start = (uint32_t)-1;
- else
- extension_range_start = iter.pos->tag;
-
- if (tag >= extension_range_start)
- {
- size_t pos = stream->bytes_left;
-
- if (!decode_extension(stream, tag, wire_type, &iter))
- return false;
-
- if (pos != stream->bytes_left)
- {
- /* The field was handled */
- continue;
- }
- }
- }
-
- /* No match found, skip data */
- if (!pb_skip_field(stream, wire_type))
- return false;
- continue;
- }
-
- /* If a repeated fixed count field was found, get size from
- * 'fixed_count_field' as there is no counter contained in the struct.
- */
- if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED
- && iter.pSize == iter.pData)
- {
- if (fixed_count_field != iter.pos) {
- /* If the new fixed count field does not match the previous one,
- * check that the previous one is NULL or that it finished
- * receiving all the expected data.
- */
- if (fixed_count_field != NULL &&
- fixed_count_size != fixed_count_field->array_size)
- {
- PB_RETURN_ERROR(stream, "wrong size for fixed count field");
- }
-
- fixed_count_field = iter.pos;
- fixed_count_size = 0;
- }
-
- iter.pSize = &fixed_count_size;
- }
-
- if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED
- && iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
- {
- uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31));
- fields_seen[iter.required_field_index >> 5] |= tmp;
- }
-
- if (!decode_field(stream, wire_type, &iter))
- return false;
- }
-
- /* Check that all elements of the last decoded fixed count field were present. */
- if (fixed_count_field != NULL &&
- fixed_count_size != fixed_count_field->array_size)
- {
- PB_RETURN_ERROR(stream, "wrong size for fixed count field");
- }
-
- /* Check that all required fields were present. */
- {
- /* First figure out the number of required fields by
- * seeking to the end of the field array. Usually we
- * are already close to end after decoding.
- */
- unsigned req_field_count;
- pb_type_t last_type;
- unsigned i;
- do {
- req_field_count = iter.required_field_index;
- last_type = iter.pos->type;
- } while (pb_field_iter_next(&iter));
-
- /* Fixup if last field was also required. */
- if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
- req_field_count++;
-
- if (req_field_count > PB_MAX_REQUIRED_FIELDS)
- req_field_count = PB_MAX_REQUIRED_FIELDS;
-
- if (req_field_count > 0)
- {
- /* Check the whole words */
- for (i = 0; i < (req_field_count >> 5); i++)
- {
- if (fields_seen[i] != allbits)
- PB_RETURN_ERROR(stream, "missing required field");
- }
-
- /* Check the remaining bits (if any) */
- if ((req_field_count & 31) != 0)
- {
- if (fields_seen[req_field_count >> 5] !=
- (allbits >> (32 - (req_field_count & 31))))
- {
- PB_RETURN_ERROR(stream, "missing required field");
- }
- }
- }
- }
-
- return true;
-}
-
-bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
- bool status;
- pb_message_set_to_defaults(fields, dest_struct);
- status = pb_decode_noinit(stream, fields, dest_struct);
-
-#ifdef PB_ENABLE_MALLOC
- if (!status)
- pb_release(fields, dest_struct);
-#endif
-
- return status;
-}
-
-bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
- pb_istream_t substream;
- bool status;
-
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- status = pb_decode_noinit(&substream, fields, dest_struct);
-
- if (!pb_close_string_substream(stream, &substream))
- return false;
- return status;
-}
-
-bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
- pb_istream_t substream;
- bool status;
-
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- status = pb_decode(&substream, fields, dest_struct);
-
- if (!pb_close_string_substream(stream, &substream))
- return false;
- return status;
-}
-
-bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
- /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */
- return pb_decode(stream, fields, dest_struct);
-}
-
-#ifdef PB_ENABLE_MALLOC
-/* Given an oneof field, if there has already been a field inside this oneof,
- * release it before overwriting with a different one. */
-static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter)
-{
- pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */
- pb_size_t new_tag = iter->pos->tag; /* New which_ value */
-
- if (old_tag == 0)
- return true; /* Ok, no old data in union */
-
- if (old_tag == new_tag)
- return true; /* Ok, old data is of same type => merge */
-
- /* Release old data. The find can fail if the message struct contains
- * invalid data. */
- if (!pb_field_iter_find(iter, old_tag))
- PB_RETURN_ERROR(stream, "invalid union tag");
-
- pb_release_single_field(iter);
-
- /* Restore iterator to where it should be.
- * This shouldn't fail unless the pb_field_t structure is corrupted. */
- if (!pb_field_iter_find(iter, new_tag))
- PB_RETURN_ERROR(stream, "iterator error");
-
- return true;
-}
-
-static void pb_release_single_field(const pb_field_iter_t *iter)
-{
- pb_type_t type;
- type = iter->pos->type;
-
- if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
- {
- if (*(pb_size_t*)iter->pSize != iter->pos->tag)
- return; /* This is not the current field in the union */
- }
-
- /* Release anything contained inside an extension or submsg.
- * This has to be done even if the submsg itself is statically
- * allocated. */
- if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
- {
- /* Release fields from all extensions in the linked list */
- pb_extension_t *ext = *(pb_extension_t**)iter->pData;
- while (ext != NULL)
- {
- pb_field_iter_t ext_iter;
- iter_from_extension(&ext_iter, ext);
- pb_release_single_field(&ext_iter);
- ext = ext->next;
- }
- }
- else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && PB_ATYPE(type) != PB_ATYPE_CALLBACK)
- {
- /* Release fields in submessage or submsg array */
- void *pItem = iter->pData;
- pb_size_t count = 1;
-
- if (PB_ATYPE(type) == PB_ATYPE_POINTER)
- {
- pItem = *(void**)iter->pData;
- }
-
- if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
- {
- if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) {
- /* No _count field so use size of the array */
- count = iter->pos->array_size;
- } else {
- count = *(pb_size_t*)iter->pSize;
- }
-
- if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size)
- {
- /* Protect against corrupted _count fields */
- count = iter->pos->array_size;
- }
- }
-
- if (pItem)
- {
- while (count--)
- {
- pb_release((const pb_field_t*)iter->pos->ptr, pItem);
- pItem = (char*)pItem + iter->pos->data_size;
- }
- }
- }
-
- if (PB_ATYPE(type) == PB_ATYPE_POINTER)
- {
- if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
- (PB_LTYPE(type) == PB_LTYPE_STRING ||
- PB_LTYPE(type) == PB_LTYPE_BYTES))
- {
- /* Release entries in repeated string or bytes array */
- void **pItem = *(void***)iter->pData;
- pb_size_t count = *(pb_size_t*)iter->pSize;
- while (count--)
- {
- pb_free(*pItem);
- *pItem++ = NULL;
- }
- }
-
- if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
- {
- /* We are going to release the array, so set the size to 0 */
- *(pb_size_t*)iter->pSize = 0;
- }
-
- /* Release main item */
- pb_free(*(void**)iter->pData);
- *(void**)iter->pData = NULL;
- }
-}
-
-void pb_release(const pb_field_t fields[], void *dest_struct)
-{
- pb_field_iter_t iter;
-
- if (!dest_struct)
- return; /* Ignore NULL pointers, similar to free() */
-
- if (!pb_field_iter_begin(&iter, fields, dest_struct))
- return; /* Empty message type */
-
- do
- {
- pb_release_single_field(&iter);
- } while (pb_field_iter_next(&iter));
-}
-#endif
-
-/* Field decoders */
-
-bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest)
-{
- pb_uint64_t value;
- if (!pb_decode_varint(stream, &value))
- return false;
-
- if (value & 1)
- *dest = (pb_int64_t)(~(value >> 1));
- else
- *dest = (pb_int64_t)(value >> 1);
-
- return true;
-}
-
-bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
-{
- union {
- uint32_t fixed32;
- pb_byte_t bytes[4];
- } u;
-
- if (!pb_read(stream, u.bytes, 4))
- return false;
-
-#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
- /* fast path - if we know that we're on little endian, assign directly */
- *(uint32_t*)dest = u.fixed32;
-#else
- *(uint32_t*)dest = ((uint32_t)u.bytes[0] << 0) |
- ((uint32_t)u.bytes[1] << 8) |
- ((uint32_t)u.bytes[2] << 16) |
- ((uint32_t)u.bytes[3] << 24);
-#endif
- return true;
-}
-
-#ifndef PB_WITHOUT_64BIT
-bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
-{
- union {
- uint64_t fixed64;
- pb_byte_t bytes[8];
- } u;
-
- if (!pb_read(stream, u.bytes, 8))
- return false;
-
-#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
- /* fast path - if we know that we're on little endian, assign directly */
- *(uint64_t*)dest = u.fixed64;
-#else
- *(uint64_t*)dest = ((uint64_t)u.bytes[0] << 0) |
- ((uint64_t)u.bytes[1] << 8) |
- ((uint64_t)u.bytes[2] << 16) |
- ((uint64_t)u.bytes[3] << 24) |
- ((uint64_t)u.bytes[4] << 32) |
- ((uint64_t)u.bytes[5] << 40) |
- ((uint64_t)u.bytes[6] << 48) |
- ((uint64_t)u.bytes[7] << 56);
-#endif
- return true;
-}
-#endif
-
-static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- pb_uint64_t value;
- pb_int64_t svalue;
- pb_int64_t clamped;
- if (!pb_decode_varint(stream, &value))
- return false;
-
- /* See issue 97: Google's C++ protobuf allows negative varint values to
- * be cast as int32_t, instead of the int64_t that should be used when
- * encoding. Previous nanopb versions had a bug in encoding. In order to
- * not break decoding of such messages, we cast <=32 bit fields to
- * int32_t first to get the sign correct.
- */
- if (field->data_size == sizeof(pb_int64_t))
- svalue = (pb_int64_t)value;
- else
- svalue = (int32_t)value;
-
- /* Cast to the proper field size, while checking for overflows */
- if (field->data_size == sizeof(pb_int64_t))
- clamped = *(pb_int64_t*)dest = svalue;
- else if (field->data_size == sizeof(int32_t))
- clamped = *(int32_t*)dest = (int32_t)svalue;
- else if (field->data_size == sizeof(int_least16_t))
- clamped = *(int_least16_t*)dest = (int_least16_t)svalue;
- else if (field->data_size == sizeof(int_least8_t))
- clamped = *(int_least8_t*)dest = (int_least8_t)svalue;
- else
- PB_RETURN_ERROR(stream, "invalid data_size");
-
- if (clamped != svalue)
- PB_RETURN_ERROR(stream, "integer too large");
-
- return true;
-}
-
-static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- pb_uint64_t value, clamped;
- if (!pb_decode_varint(stream, &value))
- return false;
-
- /* Cast to the proper field size, while checking for overflows */
- if (field->data_size == sizeof(pb_uint64_t))
- clamped = *(pb_uint64_t*)dest = value;
- else if (field->data_size == sizeof(uint32_t))
- clamped = *(uint32_t*)dest = (uint32_t)value;
- else if (field->data_size == sizeof(uint_least16_t))
- clamped = *(uint_least16_t*)dest = (uint_least16_t)value;
- else if (field->data_size == sizeof(uint_least8_t))
- clamped = *(uint_least8_t*)dest = (uint_least8_t)value;
- else
- PB_RETURN_ERROR(stream, "invalid data_size");
-
- if (clamped != value)
- PB_RETURN_ERROR(stream, "integer too large");
-
- return true;
-}
-
-static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- pb_int64_t value, clamped;
- if (!pb_decode_svarint(stream, &value))
- return false;
-
- /* Cast to the proper field size, while checking for overflows */
- if (field->data_size == sizeof(pb_int64_t))
- clamped = *(pb_int64_t*)dest = value;
- else if (field->data_size == sizeof(int32_t))
- clamped = *(int32_t*)dest = (int32_t)value;
- else if (field->data_size == sizeof(int_least16_t))
- clamped = *(int_least16_t*)dest = (int_least16_t)value;
- else if (field->data_size == sizeof(int_least8_t))
- clamped = *(int_least8_t*)dest = (int_least8_t)value;
- else
- PB_RETURN_ERROR(stream, "invalid data_size");
-
- if (clamped != value)
- PB_RETURN_ERROR(stream, "integer too large");
-
- return true;
-}
-
-static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- PB_UNUSED(field);
- return pb_decode_fixed32(stream, dest);
-}
-
-static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- PB_UNUSED(field);
-#ifndef PB_WITHOUT_64BIT
- return pb_decode_fixed64(stream, dest);
-#else
- PB_UNUSED(dest);
- PB_RETURN_ERROR(stream, "no 64bit support");
-#endif
-}
-
-static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- uint32_t size;
- size_t alloc_size;
- pb_bytes_array_t *bdest;
-
- if (!pb_decode_varint32(stream, &size))
- return false;
-
- if (size > PB_SIZE_MAX)
- PB_RETURN_ERROR(stream, "bytes overflow");
-
- alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size);
- if (size > alloc_size)
- PB_RETURN_ERROR(stream, "size too large");
-
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
- {
-#ifndef PB_ENABLE_MALLOC
- PB_RETURN_ERROR(stream, "no malloc support");
-#else
- if (!allocate_field(stream, dest, alloc_size, 1))
- return false;
- bdest = *(pb_bytes_array_t**)dest;
-#endif
- }
- else
- {
- if (alloc_size > field->data_size)
- PB_RETURN_ERROR(stream, "bytes overflow");
- bdest = (pb_bytes_array_t*)dest;
- }
-
- bdest->size = (pb_size_t)size;
- return pb_read(stream, bdest->bytes, size);
-}
-
-static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- uint32_t size;
- size_t alloc_size;
- bool status;
- if (!pb_decode_varint32(stream, &size))
- return false;
-
- /* Space for null terminator */
- alloc_size = size + 1;
-
- if (alloc_size < size)
- PB_RETURN_ERROR(stream, "size too large");
-
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
- {
-#ifndef PB_ENABLE_MALLOC
- PB_RETURN_ERROR(stream, "no malloc support");
-#else
- if (!allocate_field(stream, dest, alloc_size, 1))
- return false;
- dest = *(void**)dest;
-#endif
- }
- else
- {
- if (alloc_size > field->data_size)
- PB_RETURN_ERROR(stream, "string overflow");
- }
-
- status = pb_read(stream, (pb_byte_t*)dest, size);
- *((pb_byte_t*)dest + size) = 0;
- return status;
-}
-
-static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- bool status;
- pb_istream_t substream;
- const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr;
-
- if (!pb_make_string_substream(stream, &substream))
- return false;
-
- if (field->ptr == NULL)
- PB_RETURN_ERROR(stream, "invalid field descriptor");
-
- /* New array entries need to be initialized, while required and optional
- * submessages have already been initialized in the top-level pb_decode. */
- if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
- status = pb_decode(&substream, submsg_fields, dest);
- else
- status = pb_decode_noinit(&substream, submsg_fields, dest);
-
- if (!pb_close_string_substream(stream, &substream))
- return false;
- return status;
-}
-
-static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
- uint32_t size;
-
- if (!pb_decode_varint32(stream, &size))
- return false;
-
- if (size > PB_SIZE_MAX)
- PB_RETURN_ERROR(stream, "bytes overflow");
-
- if (size == 0)
- {
- /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */
- memset(dest, 0, field->data_size);
- return true;
- }
-
- if (size != field->data_size)
- PB_RETURN_ERROR(stream, "incorrect fixed length bytes size");
-
- return pb_read(stream, (pb_byte_t*)dest, field->data_size);
-}
diff --git a/src/lib/nanopb/pb_encode.cc b/src/lib/nanopb/pb_encode.cc
deleted file mode 100644
index f37ceec..0000000
--- a/src/lib/nanopb/pb_encode.cc
+++ /dev/null
@@ -1,893 +0,0 @@
-/* pb_encode.c -- encode a protobuf using minimal resources
- *
- * 2011 Petteri Aimonen <jpa@kapsi.fi>
- */
-
-#include "pb.h"
-#include "pb_encode.h"
-#include "pb_common.h"
-
-/* Use the GCC warn_unused_result attribute to check that all return values
- * are propagated correctly. On other compilers and gcc before 3.4.0 just
- * ignore the annotation.
- */
-#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
- #define checkreturn
-#else
- #define checkreturn __attribute__((warn_unused_result))
-#endif
-
-/**************************************
- * Declarations internal to this file *
- **************************************/
-typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
-
-static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
-static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
-static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
-static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
-static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
-static void *pb_const_cast(const void *p);
-static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high);
-static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-
-#ifdef PB_WITHOUT_64BIT
-#define pb_int64_t int32_t
-#define pb_uint64_t uint32_t
-#else
-#define pb_int64_t int64_t
-#define pb_uint64_t uint64_t
-#endif
-
-/* --- Function pointers to field encoders ---
- * Order in the array must match pb_action_t LTYPE numbering.
- */
-static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
- &pb_enc_varint,
- &pb_enc_uvarint,
- &pb_enc_svarint,
- &pb_enc_fixed32,
- &pb_enc_fixed64,
-
- &pb_enc_bytes,
- &pb_enc_string,
- &pb_enc_submessage,
- NULL, /* extensions */
- &pb_enc_fixed_length_bytes
-};
-
-/*******************************
- * pb_ostream_t implementation *
- *******************************/
-
-static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
-{
- size_t i;
- pb_byte_t *dest = (pb_byte_t*)stream->state;
- stream->state = dest + count;
-
- for (i = 0; i < count; i++)
- dest[i] = buf[i];
-
- return true;
-}
-
-pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
-{
- pb_ostream_t stream;
-#ifdef PB_BUFFER_ONLY
- stream.callback = (void*)1; /* Just a marker value */
-#else
- stream.callback = &buf_write;
-#endif
- stream.state = buf;
- stream.max_size = bufsize;
- stream.bytes_written = 0;
-#ifndef PB_NO_ERRMSG
- stream.errmsg = NULL;
-#endif
- return stream;
-}
-
-bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
-{
- if (stream->callback != NULL)
- {
- if (stream->bytes_written + count > stream->max_size)
- PB_RETURN_ERROR(stream, "stream full");
-
-#ifdef PB_BUFFER_ONLY
- if (!buf_write(stream, buf, count))
- PB_RETURN_ERROR(stream, "io error");
-#else
- if (!stream->callback(stream, buf, count))
- PB_RETURN_ERROR(stream, "io error");
-#endif
- }
-
- stream->bytes_written += count;
- return true;
-}
-
-/*************************
- * Encode a single field *
- *************************/
-
-/* Encode a static array. Handles the size calculations and possible packing. */
-static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
- const void *pData, size_t count, pb_encoder_t func)
-{
- size_t i;
- const void *p;
- size_t size;
-
- if (count == 0)
- return true;
-
- if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
- PB_RETURN_ERROR(stream, "array max size exceeded");
-
- /* We always pack arrays if the datatype allows it. */
- if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
- {
- if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
- return false;
-
- /* Determine the total size of packed array. */
- if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
- {
- size = 4 * count;
- }
- else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
- {
- size = 8 * count;
- }
- else
- {
- pb_ostream_t sizestream = PB_OSTREAM_SIZING;
- p = pData;
- for (i = 0; i < count; i++)
- {
- if (!func(&sizestream, field, p))
- return false;
- p = (const char*)p + field->data_size;
- }
- size = sizestream.bytes_written;
- }
-
- if (!pb_encode_varint(stream, (pb_uint64_t)size))
- return false;
-
- if (stream->callback == NULL)
- return pb_write(stream, NULL, size); /* Just sizing.. */
-
- /* Write the data */
- p = pData;
- for (i = 0; i < count; i++)
- {
- if (!func(stream, field, p))
- return false;
- p = (const char*)p + field->data_size;
- }
- }
- else
- {
- p = pData;
- for (i = 0; i < count; i++)
- {
- if (!pb_encode_tag_for_field(stream, field))
- return false;
-
- /* Normally the data is stored directly in the array entries, but
- * for pointer-type string and bytes fields, the array entries are
- * actually pointers themselves also. So we have to dereference once
- * more to get to the actual data. */
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
- (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
- PB_LTYPE(field->type) == PB_LTYPE_BYTES))
- {
- if (!func(stream, field, *(const void* const*)p))
- return false;
- }
- else
- {
- if (!func(stream, field, p))
- return false;
- }
- p = (const char*)p + field->data_size;
- }
- }
-
- return true;
-}
-
-/* In proto3, all fields are optional and are only encoded if their value is "non-zero".
- * This function implements the check for the zero value. */
-static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData)
-{
- pb_type_t type = field->type;
- const void *pSize = (const char*)pData + field->size_offset;
-
- if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
- {
- /* Required proto2 fields inside proto3 submessage, pretty rare case */
- return false;
- }
- else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
- {
- /* Repeated fields inside proto3 submessage: present if count != 0 */
- return *(const pb_size_t*)pSize == 0;
- }
- else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
- {
- /* Oneof fields */
- return *(const pb_size_t*)pSize == 0;
- }
- else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0)
- {
- /* Proto2 optional fields inside proto3 submessage */
- return *(const bool*)pSize == false;
- }
-
- /* Rest is proto3 singular fields */
-
- if (PB_ATYPE(type) == PB_ATYPE_STATIC)
- {
- if (PB_LTYPE(type) == PB_LTYPE_BYTES)
- {
- const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData;
- return bytes->size == 0;
- }
- else if (PB_LTYPE(type) == PB_LTYPE_STRING)
- {
- return *(const char*)pData == '\0';
- }
- else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
- {
- /* Fixed length bytes is only empty if its length is fixed
- * as 0. Which would be pretty strange, but we can check
- * it anyway. */
- return field->data_size == 0;
- }
- else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
- {
- /* Check all fields in the submessage to find if any of them
- * are non-zero. The comparison cannot be done byte-per-byte
- * because the C struct may contain padding bytes that must
- * be skipped.
- */
- pb_field_iter_t iter;
- if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData)))
- {
- do
- {
- if (!pb_check_proto3_default_value(iter.pos, iter.pData))
- {
- return false;
- }
- } while (pb_field_iter_next(&iter));
- }
- return true;
- }
- }
-
- {
- /* Catch-all branch that does byte-per-byte comparison for zero value.
- *
- * This is for all pointer fields, and for static PB_LTYPE_VARINT,
- * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also
- * callback fields. These all have integer or pointer value which
- * can be compared with 0.
- */
- pb_size_t i;
- const char *p = (const char*)pData;
- for (i = 0; i < field->data_size; i++)
- {
- if (p[i] != 0)
- {
- return false;
- }
- }
-
- return true;
- }
-}
-
-/* Encode a field with static or pointer allocation, i.e. one whose data
- * is available to the encoder directly. */
-static bool checkreturn encode_basic_field(pb_ostream_t *stream,
- const pb_field_t *field, const void *pData)
-{
- pb_encoder_t func;
- bool implicit_has;
- const void *pSize = &implicit_has;
-
- func = PB_ENCODERS[PB_LTYPE(field->type)];
-
- if (field->size_offset)
- {
- /* Static optional, repeated or oneof field */
- pSize = (const char*)pData + field->size_offset;
- }
- else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
- {
- /* Proto3 style field, optional but without explicit has_ field. */
- implicit_has = !pb_check_proto3_default_value(field, pData);
- }
- else
- {
- /* Required field, always present */
- implicit_has = true;
- }
-
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
- {
- /* pData is a pointer to the field, which contains pointer to
- * the data. If the 2nd pointer is NULL, it is interpreted as if
- * the has_field was false.
- */
- pData = *(const void* const*)pData;
- implicit_has = (pData != NULL);
- }
-
- switch (PB_HTYPE(field->type))
- {
- case PB_HTYPE_REQUIRED:
- if (!pData)
- PB_RETURN_ERROR(stream, "missing required field");
- if (!pb_encode_tag_for_field(stream, field))
- return false;
- if (!func(stream, field, pData))
- return false;
- break;
-
- case PB_HTYPE_OPTIONAL:
- if (*(const bool*)pSize)
- {
- if (!pb_encode_tag_for_field(stream, field))
- return false;
-
- if (!func(stream, field, pData))
- return false;
- }
- break;
-
- case PB_HTYPE_REPEATED: {
- pb_size_t count;
- if (field->size_offset != 0) {
- count = *(const pb_size_t*)pSize;
- } else {
- count = field->array_size;
- }
- if (!encode_array(stream, field, pData, count, func))
- return false;
- break;
- }
-
- case PB_HTYPE_ONEOF:
- if (*(const pb_size_t*)pSize == field->tag)
- {
- if (!pb_encode_tag_for_field(stream, field))
- return false;
-
- if (!func(stream, field, pData))
- return false;
- }
- break;
-
- default:
- PB_RETURN_ERROR(stream, "invalid field type");
- }
-
- return true;
-}
-
-/* Encode a field with callback semantics. This means that a user function is
- * called to provide and encode the actual data. */
-static bool checkreturn encode_callback_field(pb_ostream_t *stream,
- const pb_field_t *field, const void *pData)
-{
- const pb_callback_t *callback = (const pb_callback_t*)pData;
-
-#ifdef PB_OLD_CALLBACK_STYLE
- const void *arg = callback->arg;
-#else
- void * const *arg = &(callback->arg);
-#endif
-
- if (callback->funcs.encode != NULL)
- {
- if (!callback->funcs.encode(stream, field, arg))
- PB_RETURN_ERROR(stream, "callback error");
- }
- return true;
-}
-
-/* Encode a single field of any callback or static type. */
-static bool checkreturn encode_field(pb_ostream_t *stream,
- const pb_field_t *field, const void *pData)
-{
- switch (PB_ATYPE(field->type))
- {
- case PB_ATYPE_STATIC:
- case PB_ATYPE_POINTER:
- return encode_basic_field(stream, field, pData);
-
- case PB_ATYPE_CALLBACK:
- return encode_callback_field(stream, field, pData);
-
- default:
- PB_RETURN_ERROR(stream, "invalid field type");
- }
-}
-
-/* Default handler for extension fields. Expects to have a pb_field_t
- * pointer in the extension->type->arg field. */
-static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
- const pb_extension_t *extension)
-{
- const pb_field_t *field = (const pb_field_t*)extension->type->arg;
-
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
- {
- /* For pointer extensions, the pointer is stored directly
- * in the extension structure. This avoids having an extra
- * indirection. */
- return encode_field(stream, field, &extension->dest);
- }
- else
- {
- return encode_field(stream, field, extension->dest);
- }
-}
-
-/* Walk through all the registered extensions and give them a chance
- * to encode themselves. */
-static bool checkreturn encode_extension_field(pb_ostream_t *stream,
- const pb_field_t *field, const void *pData)
-{
- const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
- PB_UNUSED(field);
-
- while (extension)
- {
- bool status;
- if (extension->type->encode)
- status = extension->type->encode(stream, extension);
- else
- status = default_extension_encoder(stream, extension);
-
- if (!status)
- return false;
-
- extension = extension->next;
- }
-
- return true;
-}
-
-/*********************
- * Encode all fields *
- *********************/
-
-static void *pb_const_cast(const void *p)
-{
- /* Note: this casts away const, in order to use the common field iterator
- * logic for both encoding and decoding. */
- union {
- void *p1;
- const void *p2;
- } t;
- t.p2 = p;
- return t.p1;
-}
-
-bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
-{
- pb_field_iter_t iter;
- if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct)))
- return true; /* Empty message type */
-
- do {
- if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION)
- {
- /* Special case for the extension field placeholder */
- if (!encode_extension_field(stream, iter.pos, iter.pData))
- return false;
- }
- else
- {
- /* Regular field */
- if (!encode_field(stream, iter.pos, iter.pData))
- return false;
- }
- } while (pb_field_iter_next(&iter));
-
- return true;
-}
-
-bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
-{
- return pb_encode_submessage(stream, fields, src_struct);
-}
-
-bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
-{
- const pb_byte_t zero = 0;
-
- if (!pb_encode(stream, fields, src_struct))
- return false;
-
- return pb_write(stream, &zero, 1);
-}
-
-bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
-{
- pb_ostream_t stream = PB_OSTREAM_SIZING;
-
- if (!pb_encode(&stream, fields, src_struct))
- return false;
-
- *size = stream.bytes_written;
- return true;
-}
-
-/********************
- * Helper functions *
- ********************/
-
-/* This function avoids 64-bit shifts as they are quite slow on many platforms. */
-static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high)
-{
- size_t i = 0;
- pb_byte_t buffer[10];
- pb_byte_t byte = (pb_byte_t)(low & 0x7F);
- low >>= 7;
-
- while (i < 4 && (low != 0 || high != 0))
- {
- byte |= 0x80;
- buffer[i++] = byte;
- byte = (pb_byte_t)(low & 0x7F);
- low >>= 7;
- }
-
- if (high)
- {
- byte = (pb_byte_t)(byte | ((high & 0x07) << 4));
- high >>= 3;
-
- while (high)
- {
- byte |= 0x80;
- buffer[i++] = byte;
- byte = (pb_byte_t)(high & 0x7F);
- high >>= 7;
- }
- }
-
- buffer[i++] = byte;
-
- return pb_write(stream, buffer, i);
-}
-
-bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
-{
- if (value <= 0x7F)
- {
- /* Fast path: single byte */
- pb_byte_t byte = (pb_byte_t)value;
- return pb_write(stream, &byte, 1);
- }
- else
- {
-#ifdef PB_WITHOUT_64BIT
- return pb_encode_varint_32(stream, value, 0);
-#else
- return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32));
-#endif
- }
-}
-
-bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
-{
- pb_uint64_t zigzagged;
- if (value < 0)
- zigzagged = ~((pb_uint64_t)value << 1);
- else
- zigzagged = (pb_uint64_t)value << 1;
-
- return pb_encode_varint(stream, zigzagged);
-}
-
-bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
-{
- uint32_t val = *(const uint32_t*)value;
- pb_byte_t bytes[4];
- bytes[0] = (pb_byte_t)(val & 0xFF);
- bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
- bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
- bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
- return pb_write(stream, bytes, 4);
-}
-
-#ifndef PB_WITHOUT_64BIT
-bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
-{
- uint64_t val = *(const uint64_t*)value;
- pb_byte_t bytes[8];
- bytes[0] = (pb_byte_t)(val & 0xFF);
- bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
- bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
- bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
- bytes[4] = (pb_byte_t)((val >> 32) & 0xFF);
- bytes[5] = (pb_byte_t)((val >> 40) & 0xFF);
- bytes[6] = (pb_byte_t)((val >> 48) & 0xFF);
- bytes[7] = (pb_byte_t)((val >> 56) & 0xFF);
- return pb_write(stream, bytes, 8);
-}
-#endif
-
-bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
-{
- pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype;
- return pb_encode_varint(stream, tag);
-}
-
-bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
-{
- pb_wire_type_t wiretype;
- switch (PB_LTYPE(field->type))
- {
- case PB_LTYPE_VARINT:
- case PB_LTYPE_UVARINT:
- case PB_LTYPE_SVARINT:
- wiretype = PB_WT_VARINT;
- break;
-
- case PB_LTYPE_FIXED32:
- wiretype = PB_WT_32BIT;
- break;
-
- case PB_LTYPE_FIXED64:
- wiretype = PB_WT_64BIT;
- break;
-
- case PB_LTYPE_BYTES:
- case PB_LTYPE_STRING:
- case PB_LTYPE_SUBMESSAGE:
- case PB_LTYPE_FIXED_LENGTH_BYTES:
- wiretype = PB_WT_STRING;
- break;
-
- default:
- PB_RETURN_ERROR(stream, "invalid field type");
- }
-
- return pb_encode_tag(stream, wiretype, field->tag);
-}
-
-bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
-{
- if (!pb_encode_varint(stream, (pb_uint64_t)size))
- return false;
-
- return pb_write(stream, buffer, size);
-}
-
-bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
-{
- /* First calculate the message size using a non-writing substream. */
- pb_ostream_t substream = PB_OSTREAM_SIZING;
- size_t size;
- bool status;
-
- if (!pb_encode(&substream, fields, src_struct))
- {
-#ifndef PB_NO_ERRMSG
- stream->errmsg = substream.errmsg;
-#endif
- return false;
- }
-
- size = substream.bytes_written;
-
- if (!pb_encode_varint(stream, (pb_uint64_t)size))
- return false;
-
- if (stream->callback == NULL)
- return pb_write(stream, NULL, size); /* Just sizing */
-
- if (stream->bytes_written + size > stream->max_size)
- PB_RETURN_ERROR(stream, "stream full");
-
- /* Use a substream to verify that a callback doesn't write more than
- * what it did the first time. */
- substream.callback = stream->callback;
- substream.state = stream->state;
- substream.max_size = size;
- substream.bytes_written = 0;
-#ifndef PB_NO_ERRMSG
- substream.errmsg = NULL;
-#endif
-
- status = pb_encode(&substream, fields, src_struct);
-
- stream->bytes_written += substream.bytes_written;
- stream->state = substream.state;
-#ifndef PB_NO_ERRMSG
- stream->errmsg = substream.errmsg;
-#endif
-
- if (substream.bytes_written != size)
- PB_RETURN_ERROR(stream, "submsg size changed");
-
- return status;
-}
-
-/* Field encoders */
-
-static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- pb_int64_t value = 0;
-
- if (field->data_size == sizeof(int_least8_t))
- value = *(const int_least8_t*)src;
- else if (field->data_size == sizeof(int_least16_t))
- value = *(const int_least16_t*)src;
- else if (field->data_size == sizeof(int32_t))
- value = *(const int32_t*)src;
- else if (field->data_size == sizeof(pb_int64_t))
- value = *(const pb_int64_t*)src;
- else
- PB_RETURN_ERROR(stream, "invalid data_size");
-
-#ifdef PB_WITHOUT_64BIT
- if (value < 0)
- return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1);
- else
-#endif
- return pb_encode_varint(stream, (pb_uint64_t)value);
-}
-
-static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- pb_uint64_t value = 0;
-
- if (field->data_size == sizeof(uint_least8_t))
- value = *(const uint_least8_t*)src;
- else if (field->data_size == sizeof(uint_least16_t))
- value = *(const uint_least16_t*)src;
- else if (field->data_size == sizeof(uint32_t))
- value = *(const uint32_t*)src;
- else if (field->data_size == sizeof(pb_uint64_t))
- value = *(const pb_uint64_t*)src;
- else
- PB_RETURN_ERROR(stream, "invalid data_size");
-
- return pb_encode_varint(stream, value);
-}
-
-static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- pb_int64_t value = 0;
-
- if (field->data_size == sizeof(int_least8_t))
- value = *(const int_least8_t*)src;
- else if (field->data_size == sizeof(int_least16_t))
- value = *(const int_least16_t*)src;
- else if (field->data_size == sizeof(int32_t))
- value = *(const int32_t*)src;
- else if (field->data_size == sizeof(pb_int64_t))
- value = *(const pb_int64_t*)src;
- else
- PB_RETURN_ERROR(stream, "invalid data_size");
-
- return pb_encode_svarint(stream, value);
-}
-
-static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- PB_UNUSED(field);
-#ifndef PB_WITHOUT_64BIT
- return pb_encode_fixed64(stream, src);
-#else
- PB_UNUSED(src);
- PB_RETURN_ERROR(stream, "no 64bit support");
-#endif
-}
-
-static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- PB_UNUSED(field);
- return pb_encode_fixed32(stream, src);
-}
-
-static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- const pb_bytes_array_t *bytes = NULL;
-
- bytes = (const pb_bytes_array_t*)src;
-
- if (src == NULL)
- {
- /* Treat null pointer as an empty bytes field */
- return pb_encode_string(stream, NULL, 0);
- }
-
- if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
- PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
- {
- PB_RETURN_ERROR(stream, "bytes size exceeded");
- }
-
- return pb_encode_string(stream, bytes->bytes, bytes->size);
-}
-
-static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- size_t size = 0;
- size_t max_size = field->data_size;
- const char *p = (const char*)src;
-
- if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
- {
- max_size = (size_t)-1;
- }
- else
- {
- /* pb_dec_string() assumes string fields end with a null
- * terminator when the type isn't PB_ATYPE_POINTER, so we
- * shouldn't allow more than max-1 bytes to be written to
- * allow space for the null terminator.
- */
- if (max_size == 0)
- PB_RETURN_ERROR(stream, "zero-length string");
-
- max_size -= 1;
- }
-
-
- if (src == NULL)
- {
- size = 0; /* Treat null pointer as an empty string */
- }
- else
- {
- /* strnlen() is not always available, so just use a loop */
- while (size < max_size && *p != '\0')
- {
- size++;
- p++;
- }
-
- if (*p != '\0')
- {
- PB_RETURN_ERROR(stream, "unterminated string");
- }
- }
-
- return pb_encode_string(stream, (const pb_byte_t*)src, size);
-}
-
-static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- if (field->ptr == NULL)
- PB_RETURN_ERROR(stream, "invalid field descriptor");
-
- return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
-}
-
-static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
- return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size);
-}
-
diff --git a/src/lib/ubjson/ubjr.c b/src/lib/ubjson/ubjr.c
deleted file mode 100644
index 7bb2b2f..0000000
--- a/src/lib/ubjson/ubjr.c
+++ /dev/null
@@ -1,525 +0,0 @@
-#include "ubj.h"
-#include "ubj_internal.h"
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef MULTIPASS_TRACE_MALLOC
-#include "lib/mpmalloc.h"
-#else
-#define mpmalloc malloc
-#define mprealloc realloc
-#define mpfree free
-#endif
-
-#if _MSC_VER
-#define inline __inline
-#endif
-
-typedef struct ubjr_context_t_s
-{
- 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);
-
- void* userdata;
-
-// struct _ubjr_container_t container_stack[CONTAINER_STACK_MAX];
-// struct _ubjr_container_t* head;
-
- uint8_t ignore_container_flags;
-
- uint16_t last_error_code;
-
- size_t total_read;
-} ubjr_context_t;
-
-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)
- )
-{
- ubjr_context_t* ctx = (ubjr_context_t*)mpmalloc(sizeof(ubjr_context_t));
- ctx->userdata = userdata;
- ctx->read_cb = read_cb;
- ctx->peek_cb = peek_cb;
- ctx->close_cb = close_cb;
- ctx->error_cb = error_cb;
-
-
-/* ctx->head = ctx->container_stack;
- ctx->head->flags = 0;
- ctx->head->type = UBJ_MIXED;
- ctx->head->elements_remaining = 0;
-
- ctx->ignore_container_flags = 0;*/
-
- ctx->last_error_code = 0;
-
- ctx->total_read = 0;
- return ctx;
-}
-
-size_t ubjr_close_context(ubjr_context_t* ctx)
-{
- size_t n = ctx->total_read;
- mpfree(ctx->userdata);
- mpfree(ctx);
- return n;
-}
-
-static inline uint8_t priv_ubjr_context_getc(ubjr_context_t* ctx)
-{
- uint8_t a;
- ctx->total_read += 1;
- ctx->read_cb(&a, 1, 1, ctx->userdata);
- return a;
-}
-
-static int fpeek(void* fp)
-{
- int c;
- c = fgetc(fp);
- ungetc(c, fp);
-
- return c;
-}
-
-ubjr_context_t* ubjr_open_file(FILE* fd)
-{
- return ubjr_open_callback(fd, (void*)fread,(void*)fpeek,(void*)fclose, NULL);
-}
-
-struct mem_r_fd
-{
- const uint8_t *begin, *current, *end;
-};
-static int memclose(void* mfd)
-{
- //mpfree(mfd);
- return 0;
-}
-static size_t memread(void* data, size_t size, size_t count, struct mem_r_fd* fp)
-{
- size_t n = size*count;
- size_t lim = fp->end - fp->current;
- if (lim < n)
- {
- n = lim;
- }
- memcpy(data, fp->current, n);
- fp->current += n;
- return n;
-}
-static int mempeek(struct mem_r_fd* mfd)
-{
- return *mfd->current;
-}
-
-ubjr_context_t* ubjr_open_memory(const uint8_t* be, const uint8_t* en)
-{
- struct mem_r_fd* mfd = (struct mem_r_fd*)mpmalloc(sizeof(struct mem_r_fd));
- mfd->current = be;
- mfd->begin = be;
- mfd->end = en;
- return ubjr_open_callback(mfd, (void*)memread, (void*)mempeek,(void*)memclose, NULL);
-}
-
-static inline int priv_ubjr_context_peek(ubjr_context_t* ctx)
-{
- return ctx->peek_cb(ctx->userdata);
-}
-static inline size_t priv_ubjr_context_read(ubjr_context_t* ctx,uint8_t* dst,size_t n)
-{
- size_t nr=ctx->read_cb(dst,n,1,ctx->userdata);
- ctx->total_read+=nr;
- return nr;
-}
-
-typedef struct priv_ubjr_sorted_key_t_s
-{
- ubjr_string_t key;
- const uint8_t* value;
-
-} priv_ubjr_sorted_key_t;
-
-static int _obj_key_cmp(const void* av, const void* bv)
-{
- const priv_ubjr_sorted_key_t *a, *b;
- a = (const priv_ubjr_sorted_key_t*)av;
- b = (const priv_ubjr_sorted_key_t*)bv;
- return strcmp(a->key,b->key);
-}
-
-static inline UBJ_TYPE priv_ubjr_type_from_char(uint8_t c)
-{
- int i = 0; //TODO: Benchmark this and see if it should be a switch statement where the compiler implements fastest switch e.g. binary search (17 cases might be binary search fast)
- for (i = 0; i < UBJ_NUM_TYPES && UBJI_TYPEC_convert[i] != c; i++);
- return (UBJ_TYPE)i;
-}
-
-size_t ubjr_local_type_size(UBJ_TYPE typ)
-{
- return UBJR_TYPE_localsize[typ];
-}
-
-
-static inline priv_ubjr_sorted_key_t* priv_ubjr_object_build_sorted_keys(ubjr_object_t* obj)
-{
- priv_ubjr_sorted_key_t* sorted_keysmem = mpmalloc(obj->size*sizeof(priv_ubjr_sorted_key_t));
- size_t i;
- for (i = 0; i < obj->size; i++)
- {
- sorted_keysmem[i].key = obj->keys[i];
- sorted_keysmem[i].value = (const uint8_t*)obj->values + i*UBJR_TYPE_localsize[obj->type];
- }
- qsort(sorted_keysmem, obj->size, sizeof(priv_ubjr_sorted_key_t), _obj_key_cmp);
- return sorted_keysmem;
-}
-
-static inline uint8_t priv_ubjr_read_1b(ubjr_context_t* ctx)
-{
- return priv_ubjr_context_getc(ctx);
-}
-static inline uint16_t priv_ubjr_read_2b(ubjr_context_t* ctx)
-{
- return (uint16_t)priv_ubjr_read_1b(ctx) << 8 | (uint16_t)priv_ubjr_read_1b(ctx);
-}
-static inline uint32_t priv_ubjr_read_4b(ubjr_context_t* ctx)
-{
- return (uint32_t)priv_ubjr_read_2b(ctx) << 16 | (uint32_t)priv_ubjr_read_2b(ctx);
-}
-static inline uint64_t priv_ubjr_read_8b(ubjr_context_t* ctx)
-{
- return (uint64_t)priv_ubjr_read_4b(ctx) << 32 | (uint64_t)priv_ubjr_read_4b(ctx);
-}
-
-static inline int64_t priv_ubjw_read_integer(ubjr_context_t* ctx)
-{
- ubjr_dynamic_t d = ubjr_read_dynamic(ctx);
- if (d.type >= UBJ_INT8 && d.type <= UBJ_INT64)
- return d.integer;
- return 0;//error
-}
-
-static inline ubjr_object_t priv_ubjr_read_raw_object(ubjr_context_t* ctx);
-static inline ubjr_array_t priv_ubjr_read_raw_array(ubjr_context_t* ctx);
-static inline void priv_ubjr_read_to_ptr(ubjr_context_t* ctx, uint8_t* dst, UBJ_TYPE typ)
-{
- int64_t n = 1;
- char *tstr;
- switch (typ)
- {
- case UBJ_MIXED:
- {
- *(ubjr_dynamic_t*)dst = ubjr_read_dynamic(ctx);
- break;
- }
- case UBJ_STRING:
- case UBJ_HIGH_PRECISION:
- {
- n = priv_ubjw_read_integer(ctx);
- }
- case UBJ_CHAR:
- {
- tstr = mpmalloc(n + 1);
- priv_ubjr_context_read(ctx, tstr, n);
- tstr[n] = 0;
- *(ubjr_string_t*)dst = tstr;
- break;
- }
- case UBJ_INT8:
- case UBJ_UINT8:
- {
- *dst = priv_ubjr_read_1b(ctx);
- break;
- }
- case UBJ_INT16:
- {
- *(uint16_t*)dst = priv_ubjr_read_2b(ctx);
- break;
- }
- case UBJ_INT32:
- case UBJ_FLOAT32:
- {
- *(uint32_t*)dst = priv_ubjr_read_4b(ctx);
- break;
- }
- case UBJ_INT64:
- case UBJ_FLOAT64:
- {
- *(uint64_t*)dst = priv_ubjr_read_8b(ctx);
- break;
- }
- case UBJ_ARRAY:
- {
- *(ubjr_array_t*)dst = priv_ubjr_read_raw_array(ctx);
- break;
- }
- case UBJ_OBJECT:
- {
- *(ubjr_object_t*)dst = priv_ubjr_read_raw_object(ctx);
- break;
- }
- };
-}
-
-ubjr_dynamic_t ubjr_object_lookup(ubjr_object_t* obj, const char* key)
-{
- if (obj->metatable == NULL)
- {
- //memcpy(obj->sorted_keys,obj->keys)
- obj->metatable = priv_ubjr_object_build_sorted_keys(obj);
- }
- void* result=bsearch(key, obj->metatable,obj->size, sizeof(priv_ubjr_sorted_key_t),_obj_key_cmp);
- if (result == NULL)
- {
- ubjr_dynamic_t nulldyn;
- nulldyn.type = UBJ_NULLTYPE;
- return nulldyn;
- }
- const priv_ubjr_sorted_key_t* result_key = (const priv_ubjr_sorted_key_t*)result;
- return priv_ubjr_pointer_to_dynamic(obj->type,result_key->value);
-}
-
-size_t ubjr_ndarray_index(const ubjr_array_t* arr, const size_t* indices)
-{
- //multi-dimensional array to linear array lookup
- size_t cstride = 1;
- size_t cdex = 0;
- uint8_t i;
- uint8_t nd = arr->num_dims;
- const size_t* dims = arr->dims;
- for (i = 0; i<nd; i++)
- {
- cdex += cstride*indices[i];
- cstride *= dims[i];
- }
- return cdex;
-}
-
-
-
-ubjr_dynamic_t ubjr_read_dynamic(ubjr_context_t* ctx)
-{
- ubjr_dynamic_t scratch; //scratch memory
- UBJ_TYPE newtyp = priv_ubjr_type_from_char(priv_ubjr_context_getc(ctx));
- priv_ubjr_read_to_ptr(ctx, (uint8_t*)&scratch, newtyp);
- return priv_ubjr_pointer_to_dynamic(newtyp, &scratch);
-}
-
-static inline void priv_read_container_params(ubjr_context_t* ctx, UBJ_TYPE* typout, size_t* sizeout)
-{
- int nextchar = priv_ubjr_context_peek(ctx);
- if (nextchar == '$')
- {
- priv_ubjr_context_getc(ctx);
- *typout = priv_ubjr_type_from_char(priv_ubjr_context_getc(ctx));
- nextchar = priv_ubjr_context_peek(ctx);
- }
- else
- {
- *typout = UBJ_MIXED;
- }
-
- if (nextchar == '#')
- {
- priv_ubjr_context_getc(ctx);
- *sizeout = priv_ubjw_read_integer(ctx);
- }
- else
- {
- *sizeout = 0;
- }
-}
-//TODO: This can be reused for object
-
-static inline ubjr_array_t priv_ubjr_read_raw_array(ubjr_context_t* ctx)
-{
- ubjr_array_t myarray;
- priv_read_container_params(ctx,&myarray.type,&myarray.size);
- myarray.num_dims = 1;
- myarray.dims = NULL;
- if (myarray.type != UBJ_MIXED && myarray.size==0) //params detected this is a typed array but no size was detected..possibly an N-D array?
- {
- if (priv_ubjr_context_peek(ctx) == '@')
- {
- uint8_t dselect;
- priv_ubjr_context_getc(ctx);//skip over the '@' marker
- myarray.num_dims = priv_ubjr_context_getc(ctx);//since max is 8, no type indicator needed...always a int7 type
- myarray.dims = mpmalloc(sizeof(size_t)*myarray.num_dims);
- myarray.size = 1;
- for (dselect = 0; dselect < myarray.num_dims; dselect++)
- {
- size_t d = priv_ubjw_read_integer(ctx);
- myarray.dims[dselect] = d;
- myarray.size *= d;
- }
- }
- }
-
- size_t ls = UBJR_TYPE_localsize[myarray.type];
- if (myarray.size == 0)
- {
- myarray.originally_sized = 0;
- size_t arrpot = 0;
- myarray.values=mpmalloc(1*ls+1); //the +1 is for memory for the 0-size elements
- for (myarray.size = 0; priv_ubjr_context_peek(ctx) != ']'; myarray.size++)
- {
- if (myarray.size >= (1ULL << arrpot))
- {
- arrpot ++;
- myarray.values = mprealloc(myarray.values, (1ULL << arrpot)*ls+1);
- }
- priv_ubjr_read_to_ptr(ctx,(uint8_t*)myarray.values + ls*myarray.size,myarray.type);
- }
- priv_ubjr_context_getc(ctx); // read the closing ']'
- }
- else
- {
- myarray.originally_sized = 1;
- size_t i;
- myarray.values = mpmalloc(ls*myarray.size+1);
- size_t sz = UBJI_TYPE_size[myarray.type];
-
- if (sz >= 0 && myarray.type != UBJ_STRING && myarray.type != UBJ_HIGH_PRECISION && myarray.type != UBJ_CHAR && myarray.type != UBJ_MIXED) //constant size,fastread
- {
- priv_ubjr_context_read(ctx, myarray.values, sz*myarray.size);
- buf_endian_swap(myarray.values, sz, myarray.size); //do nothing for 0-sized buffers
- }
- else
- {
- for (i = 0; i < myarray.size; i++)
- {
- priv_ubjr_read_to_ptr(ctx, (uint8_t*)myarray.values + ls*i, myarray.type);
- }
- }
- }
- if (myarray.dims == NULL)
- {
- myarray.dims = mpmalloc(sizeof(size_t));
- myarray.dims[0] = myarray.size;
- }
- return myarray;
-}
-
-static inline ubjr_object_t priv_ubjr_read_raw_object(ubjr_context_t* ctx)
-{
- ubjr_object_t myobject;
- myobject.metatable = NULL;
- priv_read_container_params(ctx, &myobject.type, &myobject.size);
-
- size_t ls = UBJR_TYPE_localsize[myobject.type];
- if (myobject.size == 0)
- {
- myobject.originally_sized = 0;
- size_t arrpot = 0;
- myobject.values = mpmalloc(1 * ls + 1); //the +1 is for memory for the 0-size elements
- myobject.keys = mpmalloc(1 * sizeof(ubjr_string_t));
- for (myobject.size = 0; priv_ubjr_context_peek(ctx) != '}'; myobject.size++)
- {
- if (myobject.size >= (1ULL << arrpot))
- {
- arrpot++;
- myobject.values = mprealloc(myobject.values, (1ULL << arrpot)*ls + 1);
- myobject.keys = mprealloc((uint8_t*)myobject.keys, (1ULL << arrpot)*sizeof(ubjr_string_t));
- }
- priv_ubjr_read_to_ptr(ctx, (uint8_t*)(myobject.keys + myobject.size), UBJ_STRING);
- priv_ubjr_read_to_ptr(ctx, (uint8_t*)myobject.values + ls*myobject.size, myobject.type);
- }
- priv_ubjr_context_getc(ctx); // read the closing '}'
- }
- else
- {
- size_t i;
- myobject.originally_sized = 1;
- myobject.values = mpmalloc(ls*myobject.size + 1);
- myobject.keys = mpmalloc(myobject.size * sizeof(ubjr_string_t));
-
- for (i = 0; i < myobject.size; i++)
- {
- priv_ubjr_read_to_ptr(ctx, (uint8_t*)(myobject.keys + i), UBJ_STRING);
- priv_ubjr_read_to_ptr(ctx, (uint8_t*)myobject.values + ls*i, myobject.type);
- }
- }
- return myobject;
-}
-static inline void priv_ubjr_cleanup_pointer(UBJ_TYPE typ,void* value);
-static inline priv_ubjr_cleanup_container(UBJ_TYPE type,size_t size,void* values)
-{
- if(type == UBJ_MIXED || type == UBJ_ARRAY || type == UBJ_OBJECT || type == UBJ_STRING)
- {
- size_t ls=UBJR_TYPE_localsize[type];
- uint8_t *viter,*vend;
- viter=values;
- vend=viter+ls*size;
- for(;viter != vend;viter+=ls)
- {
- priv_ubjr_cleanup_pointer(type,(void*)viter);
- }
- }
- mpfree(values);
-}
-static inline void priv_ubjr_cleanup_pointer(UBJ_TYPE typ,void* value)
-{
- switch(typ)
- {
- case UBJ_MIXED:
- {
- ubjr_dynamic_t* dyn=(ubjr_dynamic_t*)value;
- switch(dyn->type)
- {
- case UBJ_STRING:
- priv_ubjr_cleanup_pointer(UBJ_STRING,&dyn->string);
- break;
- case UBJ_ARRAY:
- priv_ubjr_cleanup_pointer(UBJ_ARRAY,&dyn->container_array);
- break;
- case UBJ_OBJECT:
- priv_ubjr_cleanup_pointer(UBJ_OBJECT,&dyn->container_object);
- break;
- };
- break;
- }
- case UBJ_STRING:
- {
- ubjr_string_t* st=(ubjr_string_t*)value;
- mpfree((void*)*st);
- break;
- }
- case UBJ_ARRAY:
- {
- ubjr_array_t* arr=(ubjr_array_t*)value;
- priv_ubjr_cleanup_container(arr->type,arr->size,arr->values);
- mpfree(arr->dims);
- break;
- }
- case UBJ_OBJECT:
- {
- ubjr_object_t* obj=(ubjr_object_t*)value;
- priv_ubjr_cleanup_container(obj->type,obj->size,obj->values);
- priv_ubjr_cleanup_container(UBJ_STRING,obj->size,obj->keys);
- if(obj->metatable)
- {
- mpfree(obj->metatable);
- }
- break;
- }
- };
-}
-
-void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn)
-{
- priv_ubjr_cleanup_pointer(UBJ_MIXED,dyn);
-}
-void ubjr_cleanup_array(ubjr_array_t* arr)
-{
- priv_ubjr_cleanup_pointer(UBJ_ARRAY,arr);
-}
-void ubjr_cleanup_object(ubjr_object_t* obj)
-{
- priv_ubjr_cleanup_pointer(UBJ_OBJECT,obj);
-}
-
diff --git a/src/lib/ubjson/ubjrw.c b/src/lib/ubjson/ubjrw.c
deleted file mode 100644
index ee43d70..0000000
--- a/src/lib/ubjson/ubjrw.c
+++ /dev/null
@@ -1,169 +0,0 @@
-#include "ubj_internal.h"
-
-static uint32_t compute_typemask(ubjr_dynamic_t* vals, size_t sz)
-{
- uint32_t typemask = 0;
- size_t i;
- for (i = 0; i < sz; i++)
- {
- typemask |= 1UL << vals[i].type;
- }
- return typemask;
-}
-
-static inline UBJ_TYPE typemask2type(uint32_t v)
-{
- unsigned int r = 0; // r will be lg(v)
-
- while (v >>= 1) // unroll for more speed...
- {
- r++;
- }
- return (UBJ_TYPE)r;
-}
-static UBJ_TYPE compute_best_integer_type(ubjr_dynamic_t* vals, size_t sz)
-{
- uint32_t typemask = 0;
- size_t i;
- for (i = 0; i < sz; i++)
- {
- typemask |= 1UL << ubjw_min_integer_type(vals[i].integer);
- }
- return typemask2type(typemask);
-}
-static uint32_t compute_best_string_type(ubjr_dynamic_t* vals, size_t sz)
-{
- size_t i;
- for (i = 0; i < sz; i++)
- {
- if (strlen(vals[i].string) > 1)
- {
- return UBJ_STRING;
- }
- }
- return UBJ_CHAR;
-}
-static UBJ_TYPE optimize_type(UBJ_TYPE typein,ubjr_dynamic_t* vals, size_t sz)
-{
- static const uint32_t intmask = (1 << UBJ_INT8) | (1 << UBJ_UINT8) | (1 << UBJ_INT16) | (1 << UBJ_INT32) | (1 << UBJ_INT64);
- static const uint32_t stringmask = (1 << UBJ_STRING) | (1 << UBJ_CHAR);
- if (typein != UBJ_MIXED)
- return typein;
- //integer optimization can be done here...
- uint32_t tm = compute_typemask(vals, sz);
- if ((tm & intmask) == tm) //if all values are integers
- {
- return compute_best_integer_type(vals,sz); //calculate the optimum type given the data
- }
- else if ((tm & stringmask) == tm)
- {
- return compute_best_string_type(vals,sz);
- }
- else if(tm && !(tm & (tm- 1))) //if only one bit is set in typemask
- {
- return typemask2type(tm); //figure out which bit is set.
- }
- else
- {
- return UBJ_MIXED;
- }
-}
-
-void ubjrw_write_dynamic(ubjw_context_t* ctx, ubjr_dynamic_t dobj,uint8_t optimize)
-{
- UBJ_TYPE ctyp,otyp;
- size_t csize;
- uint8_t* cvalues;
- switch (dobj.type)
- {
- case UBJ_MIXED:
- return;///error, can't be mixed
- case UBJ_NULLTYPE:
- ubjw_write_null(ctx);
- return;
- case UBJ_NOOP:
- ubjw_write_noop(ctx);
- return;
- case UBJ_BOOL_FALSE:
- ubjw_write_bool(ctx, 0);
- return;
- case UBJ_BOOL_TRUE:
- ubjw_write_bool(ctx, 1);
- return;
- case UBJ_CHAR:
- ubjw_write_char(ctx, *dobj.string);//first character of string
- return;
- case UBJ_STRING:
- ubjw_write_string(ctx, dobj.string);
- return;
- case UBJ_HIGH_PRECISION:
- ubjw_write_high_precision(ctx, dobj.string);
- return;
- case UBJ_INT8:
- ubjw_write_int8(ctx, (int8_t)dobj.integer);
- return;
- case UBJ_UINT8:
- ubjw_write_uint8(ctx, (uint8_t)dobj.integer);
- return;
- case UBJ_INT16:
- ubjw_write_int16(ctx, (int16_t)dobj.integer);
- return;
- case UBJ_INT32:
- ubjw_write_int32(ctx, (int32_t)dobj.integer);
- return;
- case UBJ_INT64:
- ubjw_write_int64(ctx, dobj.integer);
- return;
- case UBJ_FLOAT32:
- ubjw_write_float32(ctx, (float)dobj.real);
- return;
- case UBJ_FLOAT64:
- ubjw_write_float64(ctx, dobj.real);
- return;
- case UBJ_ARRAY:
- if ((dobj.container_array.originally_sized || optimize) //if we optimize an unsized array to a sized one or the original is sized
- && dobj.container_array.type != UBJ_MIXED
- && dobj.container_array.type != UBJ_OBJECT
- && dobj.container_array.type != UBJ_ARRAY)
- {
- ubjw_write_buffer(ctx, dobj.container_array.values, dobj.container_array.type, dobj.container_array.size);
- return;
- }
- else
- {
- ctyp = dobj.container_array.type;
- csize = dobj.container_array.size;
- cvalues = dobj.container_array.values;
- otyp = optimize ? optimize_type(ctyp,(ubjr_dynamic_t*)cvalues,csize) : ctyp;
- ubjw_begin_array(ctx, otyp, (dobj.container_array.originally_sized || optimize) ? csize : 0);
- break;
- }
- case UBJ_OBJECT:
- {
- ctyp = dobj.container_object.type;
- csize = dobj.container_object.size;
- cvalues = dobj.container_object.values;
- otyp = optimize ? optimize_type(ctyp, (ubjr_dynamic_t*)cvalues, csize) : ctyp;
- ubjw_begin_object(ctx, otyp, (dobj.container_object.originally_sized || optimize) ? csize : 0);
- break;
- }
- };
- {
- size_t i;
- ubjr_dynamic_t scratch;
- size_t ls = UBJR_TYPE_localsize[ctyp];
-
- for (i = 0; i < csize; i++)
- {
- if (dobj.type == UBJ_OBJECT)
- {
- ubjw_write_key(ctx, dobj.container_object.keys[i]);
- }
- scratch = priv_ubjr_pointer_to_dynamic(ctyp, cvalues + ls*i);
- scratch.type = (otyp == UBJ_MIXED ? scratch.type : otyp);
- ubjrw_write_dynamic(ctx, scratch,optimize);
- }
- ubjw_end(ctx);
- }
-
-}
diff --git a/src/lib/ubjson/ubjw.c b/src/lib/ubjson/ubjw.c
deleted file mode 100644
index 9fce397..0000000
--- a/src/lib/ubjson/ubjw.c
+++ /dev/null
@@ -1,626 +0,0 @@
-#include "ubj.h"
-#include "ubj_internal.h"
-
-#ifdef MULTIPASS_TRACE_MALLOC
-#include "lib/mpmalloc.h"
-#else
-#define mpmalloc malloc
-#define mpfree free
-#endif
-
-#define CONTAINER_IS_SIZED 0x1
-#define CONTAINER_IS_TYPED 0x2
-#define CONTAINER_IS_UBJ_ARRAY 0x4
-#define CONTAINER_IS_UBJ_OBJECT 0x8
-
-#define CONTAINER_EXPECTS_KEY 0x10
-
-#define CONTAINER_STACK_MAX 16
-#define BUFFER_OUT_SIZE 1024
-
-#define MAX_DIMS 8
-
-
-struct priv_ubjw_container_t
-{
- uint8_t flags;
- UBJ_TYPE type;
- size_t elements_remaining;
-};
-
-struct ubjw_context_t_s
-{
- 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);
-
- void* userdata;
-
- struct priv_ubjw_container_t container_stack[CONTAINER_STACK_MAX];
- struct priv_ubjw_container_t* head;
-
- uint8_t ignore_container_flags;
-
- uint16_t last_error_code;
-
- size_t total_written;
-};
-
-
-
-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* ctx = (ubjw_context_t*)mpmalloc(sizeof(ubjw_context_t));
- ctx->userdata = userdata;
- ctx->write_cb = write_cb;
- ctx->close_cb = close_cb;
- ctx->error_cb = error_cb;
-
- ctx->head = ctx->container_stack;
- ctx->head->flags = 0;
- ctx->head->type = UBJ_MIXED;
- ctx->head->elements_remaining = 0;
- //ctx->head->num_dims=1;
-
- ctx->ignore_container_flags = 0;
-
- ctx->last_error_code = 0;
-
- ctx->total_written = 0;
- return ctx;
-}
-ubjw_context_t* ubjw_open_file(FILE* fd)
-{
- return ubjw_open_callback(fd, (void*)fwrite,(void*)fclose,NULL);
-}
-
-struct mem_w_fd
-{
- uint8_t *begin,*current, *end;
-};
-
-static int memclose(void* mfd)
-{
- mpfree(mfd);
- return 0;
-}
-static size_t memwrite(const void* data, size_t size, size_t count, struct mem_w_fd* fp)
-{
- size_t n = size*count;
- size_t lim = fp->end - fp->current;
- if (lim < n)
- {
- n = lim;
- }
- memcpy(fp->current, data, n);
- fp->current += n;
- return n;
-}
-
-ubjw_context_t* ubjw_open_memory(uint8_t* be, uint8_t* en)
-{
- struct mem_w_fd* mfd = (struct mem_w_fd*)mpmalloc(sizeof(struct mem_w_fd));
- mfd->current = be;
- mfd->begin = be;
- mfd->end = en;
- return ubjw_open_callback(mfd, (void*)memwrite, (void*)memclose,NULL);
-}
-
-static inline void priv_ubjw_context_append(ubjw_context_t* ctx, uint8_t a)
-{
- ctx->total_written += 1;
- ctx->write_cb(&a, 1, 1, ctx->userdata);
-}
-
-static inline void priv_disassembly_begin(ubjw_context_t* ctx)
-{
-#ifdef UBJW_DISASSEMBLY_MODE
- priv_ubjw_context_append(ctx, (uint8_t)'[');
-#endif
-}
-static inline void priv_disassembly_end(ubjw_context_t* ctx)
-{
-#ifdef UBJW_DISASSEMBLY_MODE
- priv_ubjw_context_append(ctx, (uint8_t)']');
-#endif
-}
-static inline void priv_disassembly_indent(ubjw_context_t* ctx)
-{
-#ifdef UBJW_DISASSEMBLY_MODE
- int n = ctx->head - ctx->container_stack;
- int i;
- priv_ubjw_context_append(ctx, (uint8_t)'\n');
- for (i = 0; i < n; i++)
- {
- priv_ubjw_context_append(ctx, (uint8_t)'\t');
- }
-#endif
-}
-
-static inline void priv_ubjw_context_finish_container(ubjw_context_t* ctx, struct priv_ubjw_container_t* head)
-{
- if (head->flags & CONTAINER_IS_SIZED)
- {
- if (head->elements_remaining > 0)
- {
- //error not all elements written
- }
- }
- else
- {
- priv_disassembly_begin(ctx);
- if (head->flags & CONTAINER_IS_UBJ_ARRAY)
- {
- priv_ubjw_context_append(ctx, (uint8_t)']');
- }
- else if (head->flags & CONTAINER_IS_UBJ_OBJECT)
- {
- priv_ubjw_context_append(ctx, (uint8_t)'}');
- }
- priv_disassembly_end(ctx);
- }
-}
-
-static inline priv_ubjw_container_stack_push(ubjw_context_t* ctx, const struct priv_ubjw_container_t* cnt)
-{
- size_t height = ctx->head-ctx->container_stack+1;
- if(height < CONTAINER_STACK_MAX)
- {
- *(++(ctx->head))=*cnt;
- }
- else
- {
- //todo::error
- }
-}
-static inline struct priv_ubjw_container_t priv_ubjw_container_stack_pop(ubjw_context_t* ctx)
-{
- return *ctx->head--;
-}
-
-size_t ubjw_close_context(ubjw_context_t* ctx)
-{
- while (ctx->head > ctx->container_stack)
- {
- struct priv_ubjw_container_t cnt = priv_ubjw_container_stack_pop(ctx);
- priv_ubjw_context_finish_container(ctx, &cnt);
- };
- size_t n = ctx->total_written;
- if (ctx->close_cb)
- ctx->close_cb(ctx->userdata);
- mpfree(ctx);
- return n;
-}
-
-
-static inline size_t priv_ubjw_context_write(ubjw_context_t* ctx, const uint8_t* data, size_t sz)
-{
- ctx->total_written += sz;
- return ctx->write_cb(data, 1, sz, ctx->userdata);
-}
-
-static inline void priv_ubjw_tag_public(ubjw_context_t* ctx, UBJ_TYPE tid)
-{
- struct priv_ubjw_container_t* ch = ctx->head;
- if (!ctx->ignore_container_flags)
- {
-
- /*if (
- (!(ch->flags & (CONTAINER_IS_UBJ_ARRAY | CONTAINER_IS_UBJ_OBJECT))) &&
- (tid != UBJ_ARRAY && tid !=UBJ_OBJECT))
- {
- //error, only array and object can be first written
- }*/
-
- if (ch->flags & CONTAINER_IS_UBJ_OBJECT)
- {
- if (ch->flags & CONTAINER_EXPECTS_KEY)
- {
- //error,a key expected
- return;
- }
- ch->flags |= CONTAINER_EXPECTS_KEY; //set key expected next time in this context
- }
- else
- {
- priv_disassembly_indent(ctx);
- }
-
- if (ch->flags & CONTAINER_IS_SIZED)
- {
- ch->elements_remaining--; //todo: error if elements remaining is 0;
- }
-
- if ((ch->flags & CONTAINER_IS_TYPED) && ch->type == tid)
- {
- return;
- }
- }
- priv_disassembly_begin(ctx);
- priv_ubjw_context_append(ctx, UBJI_TYPEC_convert[tid]);
- priv_disassembly_end(ctx);
-}
-
-static inline void priv_ubjw_write_raw_string(ubjw_context_t* ctx, const char* out)//TODO: possibly use a safe string
-{
- size_t n = strlen(out);
- ctx->ignore_container_flags = 1;
- ubjw_write_integer(ctx, (int64_t)n);
- ctx->ignore_container_flags = 0;
- priv_disassembly_begin(ctx);
- priv_ubjw_context_write(ctx, (const uint8_t*)out, n);
- priv_disassembly_end(ctx);
-}
-void ubjw_write_string(ubjw_context_t* ctx, const char* out)
-{
- priv_ubjw_tag_public(ctx,UBJ_STRING);
- priv_ubjw_write_raw_string(ctx, out);
-}
-
-static inline void priv_ubjw_write_raw_char(ubjw_context_t* ctx, char out)
-{
- priv_disassembly_begin(ctx);
- priv_ubjw_context_append(ctx, (uint8_t)out);
- priv_disassembly_end(ctx);
-}
-void ubjw_write_char(ubjw_context_t* ctx, char out)
-{
- priv_ubjw_tag_public(ctx,UBJ_CHAR);
- priv_ubjw_write_raw_char(ctx, out);
-}
-
-#ifndef min
-static inline size_t min(size_t x,size_t y)
-{
- return x < y ? x : y;
-}
-#endif
-
-#ifdef UBJW_DISASSEMBLY_MODE
-#include <stdarg.h>
-#define DISASSEMBLY_PRINT_BUFFER_SIZE 1024
-
-static inline priv_disassembly_print(ubjw_context_t* ctx, const char* format,...)
-{
- char buffer[DISASSEMBLY_PRINT_BUFFER_SIZE];
- va_list args;
- va_start(args, format);
- int n=vsnprintf(buffer, DISASSEMBLY_PRINT_BUFFER_SIZE, format, args);
- n = min(n, DISASSEMBLY_PRINT_BUFFER_SIZE);
- priv_ubjw_context_write(ctx, buffer,n);
- va_end(args);
-}
-#endif
-
-static inline void priv_ubjw_write_raw_uint8(ubjw_context_t* ctx, uint8_t out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- priv_ubjw_context_append(ctx, out);
-#else
- priv_disassembly_print(ctx, "%hhu", out);
-#endif
- priv_disassembly_end(ctx);
-}
-void ubjw_write_uint8(ubjw_context_t* ctx, uint8_t out)
-{
- priv_ubjw_tag_public(ctx,UBJ_UINT8);
- priv_ubjw_write_raw_uint8(ctx, out);
-}
-
-static inline void priv_ubjw_write_raw_int8(ubjw_context_t* ctx, int8_t out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- priv_ubjw_context_append(ctx, *(uint8_t*)&out);
-#else
- priv_disassembly_print(ctx, "%hhd", out);
-#endif
- priv_disassembly_end(ctx);
-}
-void ubjw_write_int8(ubjw_context_t* ctx, int8_t out)
-{
- priv_ubjw_tag_public(ctx,UBJ_INT8);
- priv_ubjw_write_raw_int8(ctx, out);
-}
-
-static inline void priv_ubjw_write_raw_int16(ubjw_context_t* ctx, int16_t out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- uint8_t buf[2];
- _to_bigendian16(buf, *(uint16_t*)&out);
- priv_ubjw_context_write(ctx, buf, 2);
-#else
- priv_disassembly_print(ctx, "%hd", out);
-#endif
- priv_disassembly_end(ctx);
-}
-void ubjw_write_int16(ubjw_context_t* ctx, int16_t out)
-{
- priv_ubjw_tag_public(ctx,UBJ_INT16);
- priv_ubjw_write_raw_int16(ctx, out);
-}
-static inline void priv_ubjw_write_raw_int32(ubjw_context_t* ctx, int32_t out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- uint8_t buf[4];
- _to_bigendian32(buf, *(uint32_t*)&out);
- priv_ubjw_context_write(ctx, buf, 4);
-#else
- priv_disassembly_print(ctx, "%ld", out);
-#endif
- priv_disassembly_end(ctx);
-}
-void ubjw_write_int32(ubjw_context_t* ctx, int32_t out)
-{
- priv_ubjw_tag_public(ctx,UBJ_INT32);
- priv_ubjw_write_raw_int32(ctx, out);
-}
-static inline void priv_ubjw_write_raw_int64(ubjw_context_t* ctx, int64_t out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- uint8_t buf[8];
- _to_bigendian64(buf, *(uint64_t*)&out);
- priv_ubjw_context_write(ctx, buf, 8);
-#else
- priv_disassembly_print(ctx, "%lld", out);
-#endif
- priv_disassembly_end(ctx);
-}
-void ubjw_write_int64(ubjw_context_t* ctx, int64_t out)
-{
- priv_ubjw_tag_public(ctx,UBJ_INT64);
- priv_ubjw_write_raw_int64(ctx, out);
-}
-
-void ubjw_write_high_precision(ubjw_context_t* ctx, const char* hp)
-{
- priv_ubjw_tag_public(ctx,UBJ_HIGH_PRECISION);
- priv_ubjw_write_raw_string(ctx, hp);
-}
-UBJ_TYPE ubjw_min_integer_type(int64_t in)
-{
- uint64_t mc = llabs(in);
- if (mc < 0x80)
- {
- return UBJ_INT8;
- }
- else if (in > 0 && mc < 0x100)
- {
- return UBJ_UINT8;
- }
- else if (mc < 0x8000)
- {
- return UBJ_INT16;
- }
- else if (mc < 0x80000000)
- {
- return UBJ_INT32;
- }
- else
- {
- return UBJ_INT64;
- }
-}
-
-void ubjw_write_integer(ubjw_context_t* ctx, int64_t out)
-{
- switch (ubjw_min_integer_type(out))
- {
- case UBJ_INT8:
- ubjw_write_int8(ctx, (int8_t)out);
- break;
- case UBJ_UINT8:
- ubjw_write_uint8(ctx, (uint8_t)out);
- break;
- case UBJ_INT16:
- ubjw_write_int16(ctx, (int16_t)out);
- break;
- case UBJ_INT32:
- ubjw_write_int32(ctx, (int32_t)out);
- break;
- default:
- ubjw_write_int64(ctx, out);
- break;
- };
-}
-
-static inline void priv_ubjw_write_raw_float32(ubjw_context_t* ctx, float out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- uint32_t fout = *(uint32_t*)&out;
- uint8_t outbuf[4];
- _to_bigendian32(outbuf, fout);
- priv_ubjw_context_write(ctx, outbuf, 4);
-#else
- priv_disassembly_print(ctx, "%g", out);
-#endif
- priv_disassembly_end(ctx);
-
-}
-void ubjw_write_float32(ubjw_context_t* ctx, float out)
-{
- priv_ubjw_tag_public(ctx,UBJ_FLOAT32);
- priv_ubjw_write_raw_float32(ctx, out);
-}
-static inline void priv_ubjw_write_raw_float64(ubjw_context_t* ctx, double out)
-{
- priv_disassembly_begin(ctx);
-#ifndef UBJW_DISASSEMBLY_MODE
- uint64_t fout = *(uint64_t*)&out;
- uint8_t outbuf[8];
- _to_bigendian64(outbuf, fout);
- priv_ubjw_context_write(ctx, outbuf, 8);
-#else
- priv_disassembly_print(ctx, "%g", out);
-#endif
- priv_disassembly_end(ctx);
-}
-void ubjw_write_float64(ubjw_context_t* ctx, double out)
-{
- priv_ubjw_tag_public(ctx,UBJ_FLOAT64);
- priv_ubjw_write_raw_float64(ctx, out);
-}
-
-void ubjw_write_floating_point(ubjw_context_t* ctx, double out)
-{
- //this may not be possible to implement correctly...for now we just write it as a float64'
- ubjw_write_float64(ctx,out);
-}
-
-void ubjw_write_noop(ubjw_context_t* ctx)
-{
- priv_ubjw_tag_public(ctx,UBJ_NOOP);
-}
-void ubjw_write_null(ubjw_context_t* ctx)
-{
- priv_ubjw_tag_public(ctx,UBJ_NULLTYPE);
-}
-void ubjw_write_bool(ubjw_context_t* ctx, uint8_t out)
-{
- priv_ubjw_tag_public(ctx,(out ? UBJ_BOOL_TRUE : UBJ_BOOL_FALSE));
-}
-
-void priv_ubjw_begin_container(struct priv_ubjw_container_t* cnt, ubjw_context_t* ctx, UBJ_TYPE typ, size_t count)
-{
- cnt->flags=0;
- cnt->elements_remaining = count;
- cnt->type = typ;
-
- if (typ != UBJ_MIXED)
- {
- if (count == 0)
- {
- //error and return;
- }
- priv_disassembly_begin(ctx);
- priv_ubjw_context_append(ctx, '$');
- priv_disassembly_end(ctx);
-
- priv_disassembly_begin(ctx);
- priv_ubjw_context_append(ctx, UBJI_TYPEC_convert[typ]);
- priv_disassembly_end(ctx);
-
- cnt->flags |= CONTAINER_IS_TYPED;
- }
- if (count != 0)
- {
- priv_disassembly_begin(ctx);
- priv_ubjw_context_append(ctx, '#');
- priv_disassembly_end(ctx);
-
- ctx->ignore_container_flags = 1;
- ubjw_write_integer(ctx, (int64_t)count);
- ctx->ignore_container_flags = 0;
-
- cnt->flags |= CONTAINER_IS_SIZED;
- cnt->elements_remaining = count;
- }
-}
-void ubjw_begin_array(ubjw_context_t* ctx, UBJ_TYPE type, size_t count)
-{
- priv_ubjw_tag_public(ctx, UBJ_ARRAY); //todo: should this happen before any erro potential?
- struct priv_ubjw_container_t ch;
- priv_ubjw_begin_container(&ch, ctx, type, count);
- ch.flags |= CONTAINER_IS_UBJ_ARRAY;
- priv_ubjw_container_stack_push(ctx, &ch);
-}
-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);
-
-void ubjw_begin_object(ubjw_context_t* ctx, UBJ_TYPE type, size_t count)
-{
- priv_ubjw_tag_public(ctx, UBJ_OBJECT);
- struct priv_ubjw_container_t ch;
- priv_ubjw_begin_container(&ch, ctx, type, count);
- ch.flags |= CONTAINER_EXPECTS_KEY | CONTAINER_IS_UBJ_OBJECT;
- priv_ubjw_container_stack_push(ctx, &ch);
-}
-void ubjw_write_key(ubjw_context_t* ctx, const char* key)
-{
- if (ctx->head->flags & CONTAINER_EXPECTS_KEY && ctx->head->flags & CONTAINER_IS_UBJ_OBJECT)
- {
- priv_disassembly_indent(ctx);
- priv_ubjw_write_raw_string(ctx, key);
- ctx->head->flags ^= CONTAINER_EXPECTS_KEY; //turn off container
- }
- else
- {
- //error unexpected key
- }
-}
-void ubjw_end(ubjw_context_t* ctx)
-{
- struct priv_ubjw_container_t ch = priv_ubjw_container_stack_pop(ctx);
- if ((ch.flags & CONTAINER_IS_UBJ_OBJECT) && !(ch.flags & CONTAINER_EXPECTS_KEY))
- {
- //error expected value
- }
- priv_disassembly_indent(ctx);
- priv_ubjw_context_finish_container(ctx, &ch);
-}
-
-
-// Not used by benchmark.py -> high BUFFER_OUT_SIZE does not matter
-static inline void priv_ubjw_write_byteswap(ubjw_context_t* ctx, const uint8_t* data, int sz, size_t count)
-{
- uint8_t buf[BUFFER_OUT_SIZE];
-
- size_t i;
- size_t nbytes = sz*count;
- for (i = 0; i < nbytes; i+=BUFFER_OUT_SIZE)
- {
- size_t npass = min(nbytes - i, BUFFER_OUT_SIZE);
- memcpy(buf, data + i, npass);
- buf_endian_swap(buf, sz, npass/sz);
- priv_ubjw_context_write(ctx, buf, npass);
- }
-}
-void ubjw_write_buffer(ubjw_context_t* ctx, const uint8_t* data, UBJ_TYPE type, size_t count)
-{
- int typesz = UBJI_TYPE_size[type];
- if (typesz < 0)
- {
- //error cannot write an STC buffer of this type.
- }
- ubjw_begin_array(ctx, type, count);
- if (type == UBJ_STRING || type == UBJ_HIGH_PRECISION)
- {
- const char** databufs = (const char**)data;
- size_t i;
- for (i = 0; i < count; i++)
- {
- priv_ubjw_write_raw_string(ctx, databufs[i]);
- }
- }
-#ifndef UBJW_DISASSEMBLY_MODE
- else if (typesz == 1 || _is_bigendian())
- {
- size_t n = typesz*count;
- priv_ubjw_context_write(ctx, data, typesz*count);
- }
- else if (typesz > 1) //and not big-endian
- {
- priv_ubjw_write_byteswap(ctx, data,typesz,count);
- }
-#else
- else
- {
- size_t i;
- for (i = 0; i < count; i++)
- {
- ubjr_dynamic_t dyn = priv_ubjr_pointer_to_dynamic(type, data + i*typesz);
- ubjrw_write_dynamic(ctx, dyn, 0);
- }
- }
-#endif
- ubjw_end(ctx);
-}
diff --git a/src/lib/xdr.cc b/src/lib/xdr.cc
deleted file mode 100644
index b44471f..0000000
--- a/src/lib/xdr.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-#include "lib/xdr.h"
-
-void XDRWriter::put(uint32_t number)
-{
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 4;
-}
-
-void XDRWriter::put(int32_t number)
-{
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 4;
-}
-
-void XDRWriter::put(uint64_t number)
-{
- *buffer++ = ((number >> 56) & 0xffU);
- *buffer++ = ((number >> 48) & 0xffU);
- *buffer++ = ((number >> 40) & 0xffU);
- *buffer++ = ((number >> 32) & 0xffU);
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 8;
-}
-
-void XDRWriter::put(int64_t number)
-{
- *buffer++ = ((number >> 56) & 0xffU);
- *buffer++ = ((number >> 48) & 0xffU);
- *buffer++ = ((number >> 40) & 0xffU);
- *buffer++ = ((number >> 32) & 0xffU);
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 8;
-}
-
-void XDRWriter::put(float number)
-{
- union {
- uint32_t i;
- float f;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.f = number;
- put(v.i);
-}
-
-void XDRWriter::put(double number)
-{
- union {
- uint64_t i;
- double d;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.d = number;
- put(v.i);
-}
-
-void XDRWriter::put(char const *data)
-{
- if (!is_fixed_length)
- {
- put(next_array_len);
- }
- uint32_t i;
- for (i = 0; i < next_array_len; i++)
- {
- *buffer++ = data[i];
- }
- while ((i++) % 4 != 0)
- {
- *buffer++ = 0;
- }
- pos += i - 1;
-}
-
-template <uint32_t TSize>
-void XDRWriter::put(char const (&data)[TSize])
-{
- if (!is_fixed_length)
- {
- put(TSize);
- }
- uint32_t i;
- for (i = 0; i < TSize; i++)
- {
- *buffer++ = data[i];
- }
- while ((i++) % 4 != 0)
- {
- *buffer++ = 0;
- }
- pos += i - 1;
-}
-
-uint32_t XDRReader::get_uint32()
-{
- uint32_t ret = (((uint32_t)data[pos] & 0xffU) << 24) | (((uint32_t)data[pos + 1] & 0xffU) << 16) | (((uint32_t)data[pos + 2] & 0xffU) << 8) | ((uint32_t)data[pos + 3] & 0xffU);
- pos += 4;
- return ret;
-}
-
-int32_t XDRReader::get_int32()
-{
- int32_t ret = (((int32_t)data[pos] & 0xff) << 24) | (((int32_t)data[pos + 1] & 0xff) << 16) | (((int32_t)data[pos + 2] & 0xff) << 8) | ((int32_t)data[pos + 3] & 0xff);
- pos += 4;
- return ret;
-}
-
-uint64_t XDRReader::get_uint64()
-{
- uint64_t ret = (((uint64_t)data[pos] & 0xffU) << 56) | (((uint64_t)data[pos + 1] & 0xffU) << 48) | (((uint64_t)data[pos + 2] & 0xffU) << 40) | (((uint64_t)data[pos + 3] & 0xffU) << 32) | (((uint64_t)data[pos + 4] & 0xffU) << 24) | (((uint64_t)data[pos + 5] & 0xffU) << 16) | (((uint64_t)data[pos + 6] & 0xffU) << 8) | ((uint64_t)data[pos + 7] & 0xffU);
- return ret;
-}
-
-int64_t XDRReader::get_int64()
-{
- int64_t ret = (((int64_t)data[pos] & 0xff) << 56) | (((int64_t)data[pos + 1] & 0xff) << 48) | (((int64_t)data[pos + 2] & 0xff) << 40) | (((int64_t)data[pos + 3] & 0xff) << 32) | (((int64_t)data[pos + 4] & 0xff) << 24) | (((int64_t)data[pos + 5] & 0xff) << 16) | (((int64_t)data[pos + 6] & 0xff) << 8) | ((int64_t)data[pos + 7] & 0xff);
- return ret;
-}
-
-float XDRReader::get_float()
-{
- union {
- uint32_t i;
- float f;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.i = get_uint32();
- return v.f;
-}
-
-double XDRReader::get_double()
-{
- union {
- uint64_t i;
- double d;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.i = get_uint64();
- return v.d;
-}
-
-uint32_t XDRReader::get_opaque_length()
-{
- return get_uint32();
-}
-
-char *XDRReader::get_opaque(uint32_t length)
-{
- char *ret = data + pos;
- pos += length;
- if (length % 4)
- {
- pos += 4 - (length % 4);
- }
- return ret;
-}
-
-void XDRReader::get_string(char *target)
-{
- uint16_t length = get_opaque_length();
- uint16_t i;
- for (i = 0; i < length; i++)
- {
- target[i] = data[pos + i];
- }
- target[i] = 0;
- pos += length;
- if (length % 4)
- {
- pos += 4 - (length % 4);
- }
-}
diff --git a/src/lib/xdr16.cc b/src/lib/xdr16.cc
deleted file mode 100644
index b1fb7ca..0000000
--- a/src/lib/xdr16.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-#include "lib/xdr16.h"
-
-void XDRWriter::put(uint16_t number)
-{
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 2;
-}
-
-void XDRWriter::put(int16_t number)
-{
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 2;
-}
-
-void XDRWriter::put(uint32_t number)
-{
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 4;
-}
-
-void XDRWriter::put(int32_t number)
-{
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 4;
-}
-
-void XDRWriter::put(uint64_t number)
-{
- *buffer++ = ((number >> 56) & 0xffU);
- *buffer++ = ((number >> 48) & 0xffU);
- *buffer++ = ((number >> 40) & 0xffU);
- *buffer++ = ((number >> 32) & 0xffU);
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 8;
-}
-
-void XDRWriter::put(int64_t number)
-{
- *buffer++ = ((number >> 56) & 0xffU);
- *buffer++ = ((number >> 48) & 0xffU);
- *buffer++ = ((number >> 40) & 0xffU);
- *buffer++ = ((number >> 32) & 0xffU);
- *buffer++ = ((number >> 24) & 0xffU);
- *buffer++ = ((number >> 16) & 0xffU);
- *buffer++ = ((number >> 8) & 0xffU);
- *buffer++ = (number & 0xffU);
- pos += 8;
-}
-
-void XDRWriter::put(float number)
-{
- union {
- uint32_t i;
- float f;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.f = number;
- put(v.i);
-}
-
-void XDRWriter::put(double number)
-{
- union {
- uint64_t i;
- double d;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.d = number;
- put(v.i);
-}
-
-void XDRWriter::put(char const *data)
-{
- if (!is_fixed_length)
- {
- put(next_array_len);
- }
- uint16_t i;
- for (i = 0; i < next_array_len; i++)
- {
- *buffer++ = data[i];
- }
- while ((i++) % 2 != 0)
- {
- *buffer++ = 0;
- }
- pos += i - 1;
-}
-
-template <uint16_t TSize>
-void XDRWriter::put(char const (&data)[TSize])
-{
- if (!is_fixed_length)
- {
- put(TSize);
- }
- uint16_t i;
- for (i = 0; i < TSize; i++)
- {
- *buffer++ = data[i];
- }
- while ((i++) % 2 != 0)
- {
- *buffer++ = 0;
- }
- pos += i - 1;
-}
-
-uint16_t XDRReader::get_uint16()
-{
- uint16_t ret = (((uint16_t)data[pos] & 0xffU) << 8) | ((uint16_t)data[pos + 1] & 0xffU);
- pos += 2;
- return ret;
-}
-
-int16_t XDRReader::get_int16()
-{
- int16_t ret = (((int16_t)data[pos] & 0xff) << 8) | ((int16_t)data[pos + 1] & 0xff);
- pos += 2;
- return ret;
-}
-
-uint32_t XDRReader::get_uint32()
-{
- uint32_t ret = (((uint32_t)data[pos] & 0xffU) << 24) | (((uint32_t)data[pos + 1] & 0xffU) << 16) | (((uint32_t)data[pos + 2] & 0xffU) << 8) | ((uint32_t)data[pos + 3] & 0xffU);
- pos += 4;
- return ret;
-}
-
-int32_t XDRReader::get_int32()
-{
- int32_t ret = (((int32_t)data[pos] & 0xff) << 24) | (((int32_t)data[pos + 1] & 0xff) << 16) | (((int32_t)data[pos + 2] & 0xff) << 8) | ((int32_t)data[pos + 3] & 0xff);
- pos += 4;
- return ret;
-}
-
-uint64_t XDRReader::get_uint64()
-{
- uint64_t ret = (((uint64_t)data[pos] & 0xffU) << 56) | (((uint64_t)data[pos + 1] & 0xffU) << 48) | (((uint64_t)data[pos + 2] & 0xffU) << 40) | (((uint64_t)data[pos + 3] & 0xffU) << 32) | (((uint64_t)data[pos + 4] & 0xffU) << 24) | (((uint64_t)data[pos + 5] & 0xffU) << 16) | (((uint64_t)data[pos + 6] & 0xffU) << 8) | ((uint64_t)data[pos + 7] & 0xffU);
- return ret;
-}
-
-int64_t XDRReader::get_int64()
-{
- int64_t ret = (((int64_t)data[pos] & 0xff) << 56) | (((int64_t)data[pos + 1] & 0xff) << 48) | (((int64_t)data[pos + 2] & 0xff) << 40) | (((int64_t)data[pos + 3] & 0xff) << 32) | (((int64_t)data[pos + 4] & 0xff) << 24) | (((int64_t)data[pos + 5] & 0xff) << 16) | (((int64_t)data[pos + 6] & 0xff) << 8) | ((int64_t)data[pos + 7] & 0xff);
- return ret;
-}
-
-float XDRReader::get_float()
-{
- union {
- uint32_t i;
- float f;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.i = get_uint32();
- return v.f;
-}
-
-double XDRReader::get_double()
-{
- union {
- uint64_t i;
- double d;
- } v;
- // Setting one member of a struct and then reading another is undefined
- // behaviour, but works as intended in nearly any (embedded) compiler
- v.i = get_uint64();
- return v.d;
-}
-
-uint32_t XDRReader::get_opaque_length()
-{
- return get_uint16();
-}
-
-char *XDRReader::get_opaque(uint32_t length)
-{
- char *ret = data + pos;
- pos += length;
- if (length % 2)
- {
- pos += 2 - (length % 2);
- }
- return ret;
-}
-
-void XDRReader::get_string(char *target)
-{
- uint16_t length = get_opaque_length();
- uint16_t i;
- for (i = 0; i < length; i++)
- {
- target[i] = data[pos + i];
- }
- target[i] = 0;
- pos += length;
- if (length % 2)
- {
- pos += 2 - (length % 2);
- }
-}