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); -	} -}  | 
