#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <memory.h> #include "binn.h" #include <ejdb2/iowow/iwutils.h> #define INT64_FORMAT PRId64 #define UINT64_FORMAT PRIu64 #define INT64_HEX_FORMAT PRIx64 #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)) #define CHUNK_SIZE 256 // 1024 #define BINN_STRUCT 1 #define BINN_BUFFER 2 void*(*malloc_fn)(size_t len) = malloc; void* (*realloc_fn)(void *ptr, size_t len) = realloc; void (*free_fn)(void *ptr) = free; #if defined(__APPLE__) || defined(_WIN32) #define __BIG_ENDIAN 0x1000 #define __LITTLE_ENDIAN 0x0001 #define __BYTE_ORDER __LITTLE_ENDIAN #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) #include <sys/endian.h> #define __BIG_ENDIAN BIG_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #define __BYTE_ORDER BYTE_ORDER #elif defined(_AIX) #include <sys/machine.h> #define __BIG_ENDIAN BIG_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #define __BYTE_ORDER BYTE_ORDER #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 #define tobe16(x) (x) #define tobe32(x) (x) #define tobe64(x) (x) #else #define tobe16(x) IW_SWAB16(x) #define tobe32(x) IW_SWAB32(x) #define tobe64(x) IW_SWAB64(x) #endif #define frombe16 tobe16 #define frombe32 tobe32 #define frombe64 tobe64 #ifndef WIN32 #define stricmp strcasecmp #define strnicmp strncasecmp #endif void 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; } ALWAYS_INLINE void *binn_malloc(int size) { return malloc_fn(size); } BINN_PRIVATE void *binn_memdup(const 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 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 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 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->writable = TRUE; item->used_size = MAX_BINN_HEADER; // save space for the header item->type = type; item->dirty = TRUE; // the header is not written to the buffer retval = TRUE; loc_exit: return retval; } binn *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 binn_create_list(binn *list) { return binn_create(list, BINN_LIST, 0, NULL); } BOOL binn_create_map(binn *map) { return binn_create(map, BINN_MAP, 0, NULL); } BOOL binn_create_object(binn *object) { return binn_create(object, BINN_OBJECT, 0, NULL); } binn *binn_list() { return binn_new(BINN_LIST, 0, 0); } binn *binn_map() { return binn_new(BINN_MAP, 0, 0); } binn *binn_object() { return binn_new(BINN_OBJECT, 0, 0); } BOOL binn_load(void *data, binn *value) { if ((data == NULL) || (value == NULL)) { return FALSE; } memset(value, 0, sizeof(binn)); value->header = BINN_MAGIC; if (binn_is_valid(data, &value->type, &value->count, &value->size) == FALSE) { return FALSE; } value->ptr = data; return TRUE; } binn *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(const void *ptr) { if (ptr == NULL) { return 0; } switch (*(const unsigned int*) ptr) { case BINN_MAGIC: return BINN_STRUCT; default: return BINN_BUFFER; } } BOOL 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, dsize; 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: 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; } memcpy(&dsize, p, 4); dsize = frombe32(dsize); p += 4 + dsize; break; case BINN_STORAGE_CONTAINER: if (p > plimit) { return 0; } dsize = *((unsigned char*) p); if (dsize & 0x80) { if (p + sizeof(int) - 1 > plimit) { return 0; } memcpy(&dsize, p, 4); dsize = frombe32(dsize); dsize &= 0x7FFFFFFF; } dsize--; // remove the type byte already added before p += dsize; break; case BINN_STORAGE_STRING: if (p > plimit) { return 0; } dsize = *((unsigned char*) p); if (dsize & 0x80) { if (p + sizeof(int) - 1 > plimit) { return 0; } memcpy(&dsize, p, 4); p += 4; dsize = frombe32(dsize); dsize &= 0x7FFFFFFF; } else { p++; } p += dsize; 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++) { memcpy(&int32, p, 4); p += 4; int32 = frombe32(int32); 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, const char *key, int keylen) { unsigned char len, *plimit, *base; int i; base = p; plimit = p + size - 1; p += header_size; // 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, const char *key, int keylen, int type, void *pvalue, int size) { unsigned char *p, len; int int32 = keylen; if ( (key == NULL) || (item == NULL) || (item->type != BINN_OBJECT) || (item->writable == FALSE) || (keylen > 255)) { return FALSE; } // is the key already in it? p = SearchForKey(item->pbuf, MAX_BINN_HEADER, item->used_size, item->count, key, keylen); 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; int int32; if ((item == NULL) || (item->type != BINN_MAP) || (item->writable == FALSE)) { return FALSE; } // is the ID already in it? p = SearchForID(item->pbuf, MAX_BINN_HEADER, item->used_size, item->count, id); if (p) { return FALSE; } if (CheckAllocation(item, 4) == FALSE) { return FALSE; // 4 bytes used for the id. } int32 = tobe32(id); p = ((unsigned char*) item->pbuf) + item->used_size; memcpy(p, &int32, 4); 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 = 0; 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) { int32_t argsz, storage_type, extra_type; uint16_t su; uint32_t lu; uint64_t llu; unsigned char *p, *ptr; 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) { pvalue = compress_int(&storage_type, &type, pvalue); } switch (storage_type) { case BINN_STORAGE_NOBYTES: size = 0; argsz = size; break; case BINN_STORAGE_BYTE: size = 1; argsz = size; break; case BINN_STORAGE_WORD: size = 2; argsz = size; break; case BINN_STORAGE_DWORD: size = 4; argsz = size; break; case BINN_STORAGE_QWORD: size = 8; argsz = size; break; case BINN_STORAGE_BLOB: if (size < 0) { return FALSE; } //if (size == 0) ... argsz = size + 4; break; case BINN_STORAGE_STRING: if (size < 0) { return FALSE; } if (size == 0) { size = strlen2((char*) pvalue); } argsz = size + 5; // at least this size break; case BINN_STORAGE_CONTAINER: if (size <= 0) { return FALSE; } argsz = size; break; default: return FALSE; } argsz += 2; // at least 2 bytes used for data_type. if (CheckAllocation(item, argsz) == 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) { ptr = (unsigned char*) &type; if (type > 255) { type = tobe16(type); // correct the endianess, if needed *p = *ptr; p++; item->used_size++; ptr++; } *p = *ptr; 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: su = *((uint16_t*) pvalue); su = tobe16(su); memcpy(p, &su, 2); item->used_size += 2; break; case BINN_STORAGE_DWORD: lu = *((uint32_t*) pvalue); lu = tobe32(lu); memcpy(p, &lu, 4); item->used_size += 4; break; case BINN_STORAGE_QWORD: // is there an htond or htonq to be used with qwords? (64 bits) llu = *((uint64_t*) pvalue); llu = tobe64(llu); memcpy(p, &llu, 8); item->used_size += 8; break; case BINN_STORAGE_BLOB: lu = tobe32(size); memcpy(p, &lu, 4); p += 4; memcpy(p, pvalue, size); item->used_size += 4 + size; break; case BINN_STORAGE_STRING: if (size > 127) { lu = size | 0x80000000; lu = tobe32(lu); memcpy(p, &lu, 4); 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; } 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; int32 = tobe32(int32); memcpy(p, &int32, 4); } else { p--; *p = (unsigned char) item->count; } // write the size if (size > 127) { p -= 4; size += 3; int32 = size | 0x80000000; int32 = tobe32(int32); memcpy(p, &int32, 4); } 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; int32 = tobe32(int32); memcpy(p, &int32, 4); p += 4; // write the count int32 = item->count | 0x80000000; int32 = tobe32(int32); memcpy(p, &int32, 4); item->ptr = item->pbuf; item->size = item->used_size; #endif item->dirty = FALSE; return TRUE; } void binn_free(binn *item) { if (item == NULL) { return; } if (item->userdata_freefn) { item->userdata_freefn(item->user_data); item->userdata_freefn = 0; } 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 *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(const void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize) { const unsigned char *p, *plimit = 0; unsigned char byte; int int32, type, size, count; if (pbuf == NULL) { return FALSE; } p = (const 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 = *((const unsigned char*) p); if (int32 & 0x80) { if (plimit && (p + sizeof(int) - 1 > plimit)) { return FALSE; } memcpy(&int32, p, 4); p += 4; int32 = frombe32(int32); int32 &= 0x7FFFFFFF; } else { p++; } size = int32; // get the count if (plimit && (p > plimit)) { return FALSE; } int32 = *((const unsigned char*) p); if (int32 & 0x80) { if (plimit && (p + sizeof(int) - 1 > plimit)) { return FALSE; } memcpy(&int32, p, 4); p += 4; int32 = frombe32(int32); int32 &= 0x7FFFFFFF; } else { p++; } count = int32; if (size < MIN_BINN_SIZE) { return FALSE; } // return the values if (ptype) { *ptype = type; } if (pcount) { *pcount = count; } if (psize && (*psize == 0)) { *psize = size; } if (pheadersize) { *pheadersize = (int) (p - (const unsigned char*) pbuf); } return TRUE; } binn *binn_copy(void *old) { int type, count, size, header_size; unsigned char *old_ptr = binn_ptr(old); binn *item; size = 0; if (!IsValidBinnHeader(old_ptr, &type, &count, &size, &header_size)) { return NULL; } item = binn_new(type, size - header_size + MAX_BINN_HEADER, NULL); if (item) { unsigned char *dest; dest = ((unsigned char*) item->pbuf) + MAX_BINN_HEADER; memcpy(dest, old_ptr + header_size, size - header_size); item->used_size = MAX_BINN_HEADER + size - header_size; item->count = count; } return item; } BOOL binn_is_valid_header(const void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize) { return IsValidBinnHeader(pbuf, ptype, pcount, psize, pheadersize); } int binn_buf_type(const void *pbuf) { int type; if (!IsValidBinnHeader(pbuf, &type, NULL, NULL, NULL)) { return INVALID_BINN; } return type; } int binn_buf_count(const void *pbuf) { int nitems; if (!IsValidBinnHeader(pbuf, NULL, &nitems, NULL, NULL)) { return 0; } return nitems; } int binn_buf_size(const void *pbuf) { int size = 0; if (!IsValidBinnHeader(pbuf, NULL, NULL, &size, NULL)) { return 0; } return size; } void *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 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 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 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 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 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 datasz; void *p2; if (value == NULL) { return FALSE; } memset(value, 0, sizeof(binn)); value->header = BINN_MAGIC; // 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: memcpy(&value->vint16, p, 2); value->vint16 = frombe16(value->vint16); value->ptr = &value->vint16; break; case BINN_STORAGE_DWORD: memcpy(&value->vint32, p, 4); value->vint32 = frombe32(value->vint32); value->ptr = &value->vint32; break; case BINN_STORAGE_QWORD: memcpy(&value->vint64, p, 8); value->vint64 = frombe64(value->vint64); value->ptr = &value->vint64; break; case BINN_STORAGE_BLOB: memcpy(&value->size, p, 4); p += 4; value->size = frombe32(value->size); 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: datasz = *((unsigned char*) p); if (datasz & 0x80) { memcpy(&datasz, p, 4); p += 4; datasz = frombe32(datasz); datasz &= 0x7FFFFFFF; } else { p++; } value->size = datasz; 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 binn_object_get_value(void *ptr, const 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, strlen(key)); if (p == FALSE) { return FALSE; } return GetValue(p, value); } BOOL 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 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 = 0, counter = 0; unsigned char *p, *plimit, *base, *key = 0, len = 0; 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: memcpy(&int32, p, 4); p += 4; int32 = frombe32(int32); if (p > plimit) { return FALSE; } id = int32; break; case BINN_OBJECT: len = *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 binn_map_get_pair(void *ptr, int pos, int *pid, binn *value) { return binn_read_pair(BINN_MAP, ptr, pos, pid, NULL, value); } BOOL binn_object_get_pair(void *ptr, int pos, char *pkey, binn *value) { return binn_read_pair(BINN_OBJECT, ptr, pos, NULL, pkey, value); } binn *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 *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 *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 *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 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 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: memcpy(&int32, p, 4); p += 4; int32 = frombe32(int32); 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 binn_read_next_pair2(int expected_type, binn_iter *iter, int *klidx, 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; } if (pkey) { *pkey = 0; } p = iter->pnext; switch (expected_type) { case BINN_MAP: memcpy(&int32, p, 4); p += 4; int32 = frombe32(int32); if (p > iter->plimit) { return FALSE; } id = int32; if (klidx) { *klidx = id; } break; case BINN_OBJECT: len = *p; p++; key = p; p += len; if (p > iter->plimit) { return FALSE; } if (klidx) { *klidx = len; } if (pkey) { *pkey = (char*) key; } break; } iter->pnext = AdvanceDataPos(p, iter->plimit); if ((iter->pnext != 0) && (iter->pnext < p)) { return FALSE; } return GetValue(p, value); } BOOL binn_map_next(binn_iter *iter, int *pid, binn *value) { return binn_read_next_pair(BINN_MAP, iter, pid, NULL, value); } BOOL binn_object_next(binn_iter *iter, char *pkey, binn *value) { return binn_read_next_pair(BINN_OBJECT, iter, NULL, pkey, value); } BOOL binn_object_next2(binn_iter *iter, char **pkey, int *klen, binn *value) { return binn_read_next_pair2(BINN_OBJECT, iter, klen, pkey, value); } binn *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 *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 *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 *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 *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 *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 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 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, const 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: case BINN_DATE: case BINN_DATETIME: case BINN_TIME: return TRUE; 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(const void *psource, void *pdest, int data_store) { switch (data_store) { case BINN_STORAGE_NOBYTES: break; case BINN_STORAGE_BYTE: *((char*) pdest) = *(const char*) psource; break; case BINN_STORAGE_WORD: *((short*) pdest) = *(const short*) psource; break; case BINN_STORAGE_DWORD: *((int*) pdest) = *(const int*) psource; break; case BINN_STORAGE_QWORD: *((uint64*) pdest) = *(const uint64*) psource; break; case BINN_STORAGE_BLOB: case BINN_STORAGE_STRING: case BINN_STORAGE_CONTAINER: *((const char**) pdest) = (const 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 = 0; int64 vf64 = 0; switch (source_type) { case BINN_INT8: vf64 = *(signed char*) psource; break; case BINN_INT16: vf64 = *(short*) psource; break; case BINN_INT32: vf64 = *(int*) psource; break; case BINN_INT64: vf64 = *(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; } vf64 = vuint64; } else if ((int_type(source_type) == BINN_SIGNED_INT) && (int_type(dest_type) == BINN_UNSIGNED_INT)) { if (vf64 < 0) { return FALSE; } vuint64 = (uint64) vf64; } switch (dest_type) { case BINN_INT8: if ((vf64 < INT8_MIN) || (vf64 > INT8_MAX)) { return FALSE; } *(signed char*) pdest = (signed char) vf64; break; case BINN_INT16: if ((vf64 < INT16_MIN) || (vf64 > INT16_MAX)) { return FALSE; } *(short*) pdest = (short) vf64; break; case BINN_INT32: if ((vf64 < INT32_MIN) || (vf64 > INT32_MAX)) { return FALSE; } *(int*) pdest = (int) vf64; break; case BINN_INT64: *(int64*) pdest = vf64; 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; } #ifdef IW_TESTS BOOL copy_int_value_tests(void *psource, void *pdest, int source_type, int dest_type) { return copy_int_value(psource, pdest, source_type, dest_type); } #endif 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) { switch (binn_get_read_storage(type)) { case BINN_STORAGE_NOBYTES: break; case BINN_STORAGE_BYTE: memset(pvalue, 0, 1); break; case BINN_STORAGE_WORD: memset(pvalue, 0, 2); break; case BINN_STORAGE_DWORD: memset(pvalue, 0, 4); break; case BINN_STORAGE_QWORD: memset(pvalue, 0, 8); break; case BINN_STORAGE_BLOB: case BINN_STORAGE_STRING: case BINN_STORAGE_CONTAINER: *(char**) pvalue = NULL; break; } } 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 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 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 binn_object_set(binn *obj, const char *key, int type, void *pvalue, int size) { if (GetWriteConvertedData(&type, &pvalue, &size) == FALSE) { return FALSE; } return binn_object_set_raw(obj, key, strlen(key), type, pvalue, size); } BOOL binn_object_set2(binn *obj, const char *key, int keylen, int type, void *pvalue, int size) { if (GetWriteConvertedData(&type, &pvalue, &size) == FALSE) { return FALSE; } return binn_object_set_raw(obj, key, keylen, type, pvalue, size); } // this function is used by the wrappers BOOL 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 binn_list_add_new(binn *list, binn *value) { BOOL retval; retval = binn_list_add_value(list, value); binn_free(value); return retval; } BOOL binn_map_set_new(binn *map, int id, binn *value) { BOOL retval; retval = binn_map_set_value(map, id, value); binn_free(value); return retval; } BOOL binn_object_set_new(binn *obj, const char *key, binn *value) { BOOL retval; retval = binn_object_set_value(obj, key, value); binn_free(value); return retval; } BOOL binn_object_set_new2(binn *obj, const char *key, int keylen, binn *value) { BOOL retval; retval = binn_object_set_value2(obj, key, keylen, value); binn_free(value); return retval; } /*** READ FUNCTIONS ******************************************************************/ binn *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 *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 *binn_object_value(void *ptr, const 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 *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 *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 *binn_object_read(void *obj, const 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 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 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; } BOOL binn_object_get(void *ptr, const 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 binn_list_int8(void *list, int pos) { signed char value; binn_list_get(list, pos, BINN_INT8, &value, NULL); return value; } short binn_list_int16(void *list, int pos) { short value; binn_list_get(list, pos, BINN_INT16, &value, NULL); return value; } int binn_list_int32(void *list, int pos) { int value; binn_list_get(list, pos, BINN_INT32, &value, NULL); return value; } int64 binn_list_int64(void *list, int pos) { int64 value; binn_list_get(list, pos, BINN_INT64, &value, NULL); return value; } unsigned char binn_list_uint8(void *list, int pos) { unsigned char value; binn_list_get(list, pos, BINN_UINT8, &value, NULL); return value; } unsigned short binn_list_uint16(void *list, int pos) { unsigned short value; binn_list_get(list, pos, BINN_UINT16, &value, NULL); return value; } unsigned int binn_list_uint32(void *list, int pos) { unsigned int value; binn_list_get(list, pos, BINN_UINT32, &value, NULL); return value; } uint64 binn_list_uint64(void *list, int pos) { uint64 value; binn_list_get(list, pos, BINN_UINT64, &value, NULL); return value; } float binn_list_float(void *list, int pos) { float value; binn_list_get(list, pos, BINN_FLOAT32, &value, NULL); return value; } double binn_list_double(void *list, int pos) { double value; binn_list_get(list, pos, BINN_FLOAT64, &value, NULL); return value; } BOOL binn_list_bool(void *list, int pos) { BOOL value; binn_list_get(list, pos, BINN_BOOL, &value, NULL); return value; } BOOL binn_list_null(void *list, int pos) { return binn_list_get(list, pos, BINN_NULL, NULL, NULL); } char *binn_list_str(void *list, int pos) { char *value; binn_list_get(list, pos, BINN_STRING, &value, NULL); return value; } void *binn_list_blob(void *list, int pos, int *psize) { void *value; binn_list_get(list, pos, BINN_BLOB, &value, psize); return value; } void *binn_list_list(void *list, int pos) { void *value; binn_list_get(list, pos, BINN_LIST, &value, NULL); return value; } void *binn_list_map(void *list, int pos) { void *value; binn_list_get(list, pos, BINN_MAP, &value, NULL); return value; } void *binn_list_object(void *list, int pos) { void *value; binn_list_get(list, pos, BINN_OBJECT, &value, NULL); return value; } signed char binn_map_int8(void *map, int id) { signed char value; binn_map_get(map, id, BINN_INT8, &value, NULL); return value; } short binn_map_int16(void *map, int id) { short value; binn_map_get(map, id, BINN_INT16, &value, NULL); return value; } int binn_map_int32(void *map, int id) { int value; binn_map_get(map, id, BINN_INT32, &value, NULL); return value; } int64 binn_map_int64(void *map, int id) { int64 value; binn_map_get(map, id, BINN_INT64, &value, NULL); return value; } unsigned char binn_map_uint8(void *map, int id) { unsigned char value; binn_map_get(map, id, BINN_UINT8, &value, NULL); return value; } unsigned short binn_map_uint16(void *map, int id) { unsigned short value; binn_map_get(map, id, BINN_UINT16, &value, NULL); return value; } unsigned int binn_map_uint32(void *map, int id) { unsigned int value; binn_map_get(map, id, BINN_UINT32, &value, NULL); return value; } uint64 binn_map_uint64(void *map, int id) { uint64 value; binn_map_get(map, id, BINN_UINT64, &value, NULL); return value; } float binn_map_float(void *map, int id) { float value; binn_map_get(map, id, BINN_FLOAT32, &value, NULL); return value; } double binn_map_double(void *map, int id) { double value; binn_map_get(map, id, BINN_FLOAT64, &value, NULL); return value; } BOOL binn_map_bool(void *map, int id) { BOOL value; binn_map_get(map, id, BINN_BOOL, &value, NULL); return value; } BOOL binn_map_null(void *map, int id) { return binn_map_get(map, id, BINN_NULL, NULL, NULL); } char *binn_map_str(void *map, int id) { char *value; binn_map_get(map, id, BINN_STRING, &value, NULL); return value; } void *binn_map_blob(void *map, int id, int *psize) { void *value; binn_map_get(map, id, BINN_BLOB, &value, psize); return value; } void *binn_map_list(void *map, int id) { void *value; binn_map_get(map, id, BINN_LIST, &value, NULL); return value; } void *binn_map_map(void *map, int id) { void *value; binn_map_get(map, id, BINN_MAP, &value, NULL); return value; } void *binn_map_object(void *map, int id) { void *value; binn_map_get(map, id, BINN_OBJECT, &value, NULL); return value; } signed char binn_object_int8(void *obj, const char *key) { signed char value; binn_object_get(obj, key, BINN_INT8, &value, NULL); return value; } short binn_object_int16(void *obj, const char *key) { short value; binn_object_get(obj, key, BINN_INT16, &value, NULL); return value; } int binn_object_int32(void *obj, const char *key) { int value; binn_object_get(obj, key, BINN_INT32, &value, NULL); return value; } int64 binn_object_int64(void *obj, const char *key) { int64 value; binn_object_get(obj, key, BINN_INT64, &value, NULL); return value; } unsigned char binn_object_uint8(void *obj, const char *key) { unsigned char value; binn_object_get(obj, key, BINN_UINT8, &value, NULL); return value; } unsigned short binn_object_uint16(void *obj, const char *key) { unsigned short value; binn_object_get(obj, key, BINN_UINT16, &value, NULL); return value; } unsigned int binn_object_uint32(void *obj, const char *key) { unsigned int value; binn_object_get(obj, key, BINN_UINT32, &value, NULL); return value; } uint64 binn_object_uint64(void *obj, const char *key) { uint64 value; binn_object_get(obj, key, BINN_UINT64, &value, NULL); return value; } float binn_object_float(void *obj, const char *key) { float value; binn_object_get(obj, key, BINN_FLOAT32, &value, NULL); return value; } double binn_object_double(void *obj, const char *key) { double value; binn_object_get(obj, key, BINN_FLOAT64, &value, NULL); return value; } BOOL binn_object_bool(void *obj, const char *key) { BOOL value; binn_object_get(obj, key, BINN_BOOL, &value, NULL); return value; } BOOL binn_object_null(void *obj, const char *key) { return binn_object_get(obj, key, BINN_NULL, NULL, NULL); } char *binn_object_str(void *obj, const char *key) { char *value; binn_object_get(obj, key, BINN_STRING, &value, NULL); return value; } void *binn_object_blob(void *obj, const char *key, int *psize) { void *value; binn_object_get(obj, key, BINN_BLOB, &value, psize); return value; } void *binn_object_list(void *obj, const char *key) { void *value; binn_object_get(obj, key, BINN_LIST, &value, NULL); return value; } void *binn_object_map(void *obj, const char *key) { void *value; binn_object_get(obj, key, BINN_MAP, &value, NULL); return value; } void *binn_object_object(void *obj, const 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; } return item; } binn *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((const 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 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 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 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: *pint = round(value->vfloat); break; case BINN_DOUBLE: *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 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: *pint = round(value->vfloat); break; case BINN_DOUBLE: *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 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 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 *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; } snprintf(buf, sizeof(buf), "%" INT64_FORMAT, vint); // -V576 goto loc_convert_value; } switch (value->type) { case BINN_FLOAT: value->vdouble = value->vfloat; case BINN_DOUBLE: snprintf(buf, sizeof(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->ptr = strdup(buf); if (value->ptr == NULL) { return NULL; } value->freefn = free; value->type = BINN_STRING; return (char*) value->ptr; } /*** GENERAL FUNCTIONS ***************************************************************/ BOOL 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; } } void binn_set_user_data(binn *item, void *user_data, binn_user_data_free freefn) { if (item->userdata_freefn) { item->userdata_freefn(item->user_data); } item->user_data = user_data; item->userdata_freefn = free_fn; }