diff options
author | Daniel Friesel <daniel.friesel@uos.de> | 2020-09-07 12:57:04 +0200 |
---|---|---|
committer | Daniel Friesel <daniel.friesel@uos.de> | 2020-09-07 12:57:04 +0200 |
commit | 0558244645611f314f47e0fa427f7323ce253eaf (patch) | |
tree | 824bcd55ec8577703345106d0a08e167407500a7 /src/lib | |
parent | 0248c6352f2117e50fac71dd632a79d8fa4f8737 (diff) |
remove external libraries from main branch
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/binn.cc | 3372 | ||||
-rw-r--r-- | src/lib/capnp-c/capn-malloc.cc | 424 | ||||
-rw-r--r-- | src/lib/capnp-c/capn-stream.cc | 217 | ||||
-rw-r--r-- | src/lib/capnp-c/capn.cc | 1117 | ||||
-rw-r--r-- | src/lib/mpack/mpack.cc | 6440 | ||||
-rw-r--r-- | src/lib/mpmalloc.cc | 42 | ||||
-rw-r--r-- | src/lib/nanopb/pb_common.cc | 97 | ||||
-rw-r--r-- | src/lib/nanopb/pb_decode.cc | 1528 | ||||
-rw-r--r-- | src/lib/nanopb/pb_encode.cc | 893 | ||||
-rw-r--r-- | src/lib/ubjson/ubjr.c | 525 | ||||
-rw-r--r-- | src/lib/ubjson/ubjrw.c | 169 | ||||
-rw-r--r-- | src/lib/ubjson/ubjw.c | 626 | ||||
-rw-r--r-- | src/lib/xdr.cc | 188 | ||||
-rw-r--r-- | src/lib/xdr16.cc | 216 |
14 files changed, 0 insertions, 15854 deletions
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); - } -} |