2025-09-20 23:15:04 -05:00
|
|
|
#include <stdint.h>
|
2025-09-15 01:17:36 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "empack.h"
|
|
|
|
|
|
|
|
|
|
#define EMPACK_POS_FIXINT_MAX (0x7f)
|
|
|
|
|
#define EMPACK_FIXMAP_MAX (0x8f)
|
|
|
|
|
#define EMPACK_FIXARRAY_MAX (0x9f)
|
|
|
|
|
#define EMPACK_FIXSTR_MAX (0xbf)
|
|
|
|
|
#define EMPACK_NEG_FIXINT_MAX (0xff)
|
|
|
|
|
|
|
|
|
|
/** Attempt to allocate size bytes from the memory arena, NULL if out of memory */
|
|
|
|
|
static void *empack_allocate(empack_t *empack, uint32_t size);
|
|
|
|
|
|
|
|
|
|
/** Copy src to dst but with reversed byte order */
|
|
|
|
|
static void memswap(uint8_t *dst, const uint8_t *src, uint32_t len);
|
|
|
|
|
/** Convert a big-endian UINT16 buffer to native uint16_t */
|
|
|
|
|
static uint16_t buf_to_u16(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian UINT32 buffer to native uint32_t */
|
|
|
|
|
static uint32_t buf_to_u32(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian UINT64 buffer to native uint64_t */
|
|
|
|
|
static uint64_t buf_to_u64(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian INT16 buffer to native int16_t */
|
|
|
|
|
static int16_t buf_to_i16(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian INT32 buffer to native int32_t */
|
|
|
|
|
static int32_t buf_to_i32(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian INT64 buffer to native int64_t */
|
|
|
|
|
static int64_t buf_to_i64(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian FLOAT32 buffer to native float */
|
|
|
|
|
static float buf_to_float(const uint8_t *buf);
|
|
|
|
|
/** Convert a big-endian FLOAT64 buffer to native double */
|
|
|
|
|
static double buf_to_double(const uint8_t *buf);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
empack_init(empack_t *empack, void *arena, uint32_t arena_sz)
|
|
|
|
|
{
|
|
|
|
|
empack->arena = arena;
|
|
|
|
|
empack->arena_sz = arena_sz;
|
|
|
|
|
empack->arena_used = 0;
|
|
|
|
|
|
|
|
|
|
memset(arena, 0, arena_sz);
|
2025-09-20 23:15:04 -05:00
|
|
|
memset(&empack->root, 0, sizeof(empack->root));
|
2025-09-15 01:17:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
empack_status_e
|
|
|
|
|
empack_parse(empack_t *empack, const void *msgpack, uint32_t len)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *buf = (const uint8_t *)msgpack;
|
|
|
|
|
uint32_t p = 0;
|
|
|
|
|
empack_status_e ret;
|
|
|
|
|
empack_obj_t *cur = &empack->root;
|
|
|
|
|
empack_obj_t *parent = NULL;
|
|
|
|
|
uint32_t tokens_needed = 1;
|
|
|
|
|
|
|
|
|
|
while (tokens_needed > 0) {
|
|
|
|
|
uint32_t len_used;
|
|
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
|
switch (parent->type) {
|
|
|
|
|
case EMPACK_TYPE_FIXARRAY:
|
|
|
|
|
case EMPACK_TYPE_ARRAY16:
|
|
|
|
|
case EMPACK_TYPE_ARRAY32:
|
|
|
|
|
{
|
|
|
|
|
empack_array_t *parr = &parent->val.array;
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
if (parr->object_count == parr->objects_parsed) {
|
2025-09-15 01:17:36 -05:00
|
|
|
ret = EMPACK_STATUS_ERROR;
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
cur->next = &parr->objects[parr->objects_parsed];
|
|
|
|
|
cur = cur->next;
|
2025-09-15 01:17:36 -05:00
|
|
|
cur->parent = parent;
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
parr->objects_parsed++;
|
|
|
|
|
if (parr->object_count == parr->objects_parsed) {
|
2025-09-15 01:17:36 -05:00
|
|
|
parent = parent->parent;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case EMPACK_TYPE_FIXMAP:
|
|
|
|
|
case EMPACK_TYPE_MAP16:
|
|
|
|
|
case EMPACK_TYPE_MAP32:
|
|
|
|
|
{
|
|
|
|
|
empack_map_t *pmap = &parent->val.map;
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
if (pmap->pair_count == pmap->pairs_parsed) {
|
2025-09-15 01:17:36 -05:00
|
|
|
ret = EMPACK_STATUS_ERROR;
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
if (pmap->pairs[pmap->pairs_parsed].key.type == EMPACK_TYPE_ERROR) {
|
2025-09-15 01:17:36 -05:00
|
|
|
/* We haven't parsed the key yet */
|
2025-09-20 23:15:04 -05:00
|
|
|
cur->next = &pmap->pairs[pmap->pairs_parsed].key;
|
2025-09-15 01:17:36 -05:00
|
|
|
} else {
|
2025-09-20 23:15:04 -05:00
|
|
|
cur->next = &pmap->pairs[pmap->pairs_parsed].value;
|
|
|
|
|
pmap->pairs_parsed++;
|
2025-09-15 01:17:36 -05:00
|
|
|
}
|
2025-09-20 23:15:04 -05:00
|
|
|
cur = cur->next;
|
2025-09-15 01:17:36 -05:00
|
|
|
cur->parent = parent;
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
if (pmap->pair_count == pmap->pairs_parsed) {
|
2025-09-15 01:17:36 -05:00
|
|
|
parent = parent->parent;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
ret = EMPACK_STATUS_ERROR;
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
len_used = len - p;
|
|
|
|
|
ret = empack_parse_one(cur, &buf[p], &len_used);
|
|
|
|
|
if ((ret != EMPACK_STATUS_COMPLETE) && (ret != EMPACK_STATUS_EXTRA)) {
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p += len_used;
|
|
|
|
|
tokens_needed--;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (cur->type) {
|
|
|
|
|
case EMPACK_TYPE_FIXARRAY:
|
|
|
|
|
case EMPACK_TYPE_ARRAY16:
|
|
|
|
|
case EMPACK_TYPE_ARRAY32:
|
|
|
|
|
{
|
|
|
|
|
empack_array_t *parr = &cur->val.array;
|
|
|
|
|
|
2025-09-21 20:01:16 -05:00
|
|
|
if (parr->object_count == 0) {
|
|
|
|
|
/* nothing to do on an empty array */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-15 01:17:36 -05:00
|
|
|
parr->objects = empack_allocate(empack, sizeof(empack_obj_t) * parr->object_count);
|
|
|
|
|
if (parr->objects == NULL) {
|
|
|
|
|
ret = EMPACK_STATUS_NOMEM;
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tokens_needed += parr->object_count;
|
|
|
|
|
parent = cur;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXMAP:
|
|
|
|
|
case EMPACK_TYPE_MAP16:
|
|
|
|
|
case EMPACK_TYPE_MAP32:
|
|
|
|
|
{
|
|
|
|
|
empack_map_t *pmap = &cur->val.map;
|
|
|
|
|
|
2025-09-21 20:01:16 -05:00
|
|
|
if (pmap->pair_count == 0) {
|
|
|
|
|
/* nothing to do on an empty map */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-15 01:17:36 -05:00
|
|
|
pmap->pairs = empack_allocate(empack, sizeof(empack_map_t) * pmap->pair_count);
|
|
|
|
|
if (pmap->pairs == NULL) {
|
|
|
|
|
ret = EMPACK_STATUS_NOMEM;
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize the key objects to a type of error so we can tell if
|
|
|
|
|
* we've already parsed them when we loop back around to parse the
|
|
|
|
|
* value */
|
|
|
|
|
for (uint32_t i = 0; i < pmap->pair_count; i++) {
|
|
|
|
|
pmap->pairs[i].key.type = EMPACK_TYPE_ERROR;
|
|
|
|
|
}
|
2025-09-16 02:26:22 -05:00
|
|
|
|
|
|
|
|
tokens_needed += pmap->pair_count * 2;
|
|
|
|
|
parent = cur;
|
2025-09-15 01:17:36 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-09-20 23:15:04 -05:00
|
|
|
|
|
|
|
|
if ((tokens_needed == 0) && (ret == EMPACK_STATUS_EXTRA)) {
|
|
|
|
|
goto empack_parse_return;
|
|
|
|
|
}
|
2025-09-15 01:17:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* prioritize errors over incomplete status */
|
|
|
|
|
if ((ret == EMPACK_STATUS_COMPLETE) && (p < len)) {
|
|
|
|
|
ret = EMPACK_STATUS_WANT_MORE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
empack_parse_return:
|
|
|
|
|
return (ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
empack_status_e
|
|
|
|
|
empack_parse_one(empack_obj_t *object, const void *msgpack, uint32_t *len)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *buf = (const uint8_t *)msgpack;
|
|
|
|
|
uint32_t p = 0;
|
|
|
|
|
empack_status_e ret = EMPACK_STATUS_EXTRA;
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
memset(&object->val, 0, sizeof(object->val));
|
2025-09-15 01:17:36 -05:00
|
|
|
|
|
|
|
|
#define EMPACK_PARSEONE_ASSERT(need) do { \
|
|
|
|
|
if ((p + (need)) > (*len)) { \
|
|
|
|
|
ret = EMPACK_STATUS_ERROR; \
|
|
|
|
|
goto empack_parse_one_return; \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
/* this casting will be validated for object types with a range */
|
|
|
|
|
object->type = (empack_type_e)buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
|
|
|
|
|
switch (object->type) {
|
|
|
|
|
case EMPACK_TYPE_NIL:
|
|
|
|
|
case EMPACK_TYPE_TRUE:
|
|
|
|
|
case EMPACK_TYPE_FALSE:
|
|
|
|
|
/* no extra value associated for these types */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_BIN8:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.bin.size = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.bin.size);
|
|
|
|
|
object->val.bin.data = &buf[p];
|
|
|
|
|
p += object->val.bin.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_BIN16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.bin.size = buf_to_u16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.bin.size);
|
|
|
|
|
object->val.bin.data = &buf[p];
|
|
|
|
|
p += object->val.bin.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_BIN32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.bin.size = buf_to_u32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.bin.size);
|
|
|
|
|
object->val.bin.data = &buf[p];
|
|
|
|
|
p += object->val.bin.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_EXT8:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.size = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.ext.size);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
p += object->val.ext.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_EXT16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.ext.size = buf_to_u16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.ext.size);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
p += object->val.ext.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_EXT32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.ext.size = buf_to_u32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.ext.size);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
p += object->val.ext.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FLOAT32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.float32 = buf_to_float(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FLOAT64:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(8);
|
|
|
|
|
object->val.float64 = buf_to_double(&buf[p]);
|
|
|
|
|
p += 8;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_UINT8:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.uint8 = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_UINT16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.uint16 = buf_to_u16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_UINT32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.uint16 = buf_to_u32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_UINT64:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(8);
|
|
|
|
|
object->val.uint64 = buf_to_u64(&buf[p]);
|
|
|
|
|
p += 8;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_INT8:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.int8 = (int8_t)buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_INT16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.int16 = buf_to_i16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_INT32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.int32 = buf_to_i32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_INT64:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(8);
|
|
|
|
|
object->val.int64 = buf_to_i64(&buf[p]);
|
|
|
|
|
p += 8;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXEXT1:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
object->val.ext.size = 1;
|
|
|
|
|
p += 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXEXT2:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
object->val.ext.size = 2;
|
|
|
|
|
p += 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXEXT4:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
object->val.ext.size = 4;
|
|
|
|
|
p += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXEXT8:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(8);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
object->val.ext.size = 8;
|
|
|
|
|
p += 8;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXEXT16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.ext.type = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(16);
|
|
|
|
|
object->val.ext.data = &buf[p];
|
|
|
|
|
object->val.ext.size = 16;
|
|
|
|
|
p += 16;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_STR8:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(1);
|
|
|
|
|
object->val.str.size = buf[p];
|
|
|
|
|
p += 1;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.str.size);
|
|
|
|
|
object->val.str.data = (const char *)&buf[p];
|
|
|
|
|
p += object->val.str.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_STR16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.str.size = buf_to_u16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.str.size);
|
|
|
|
|
object->val.str.data = (const char *)&buf[p];
|
|
|
|
|
p += object->val.str.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_STR32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.str.size = buf_to_u32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.str.size);
|
|
|
|
|
object->val.str.data = (const char *)&buf[p];
|
|
|
|
|
p += object->val.str.size;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_ARRAY16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.array.object_count = buf_to_u16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_ARRAY32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.array.object_count = buf_to_u32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_MAP16:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(2);
|
|
|
|
|
object->val.map.pair_count = buf_to_u16(&buf[p]);
|
|
|
|
|
p += 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_MAP32:
|
|
|
|
|
EMPACK_PARSEONE_ASSERT(4);
|
|
|
|
|
object->val.map.pair_count = buf_to_u32(&buf[p]);
|
|
|
|
|
p += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if ((object->type >= EMPACK_TYPE_POS_FIXINT) && (object->type <= EMPACK_POS_FIXINT_MAX)) {
|
|
|
|
|
object->val.uint8 = (uint8_t)object->type;
|
|
|
|
|
object->type = EMPACK_TYPE_POS_FIXINT;
|
|
|
|
|
}
|
|
|
|
|
else if ((object->type >= EMPACK_TYPE_FIXMAP) && (object->type <= EMPACK_FIXMAP_MAX)) {
|
|
|
|
|
object->val.map.pair_count = ((uint8_t)object->type) & 0x0f;
|
|
|
|
|
object->type = EMPACK_TYPE_FIXMAP;
|
|
|
|
|
}
|
|
|
|
|
else if ((object->type >= EMPACK_TYPE_FIXSTR) && (object->type <= EMPACK_FIXSTR_MAX)) {
|
|
|
|
|
object->val.str.size = ((uint8_t)object->type) & 0x1f;
|
2025-09-20 23:15:04 -05:00
|
|
|
EMPACK_PARSEONE_ASSERT(object->val.str.size);
|
|
|
|
|
object->val.str.data = (const char *)&buf[p];
|
2025-09-15 01:17:36 -05:00
|
|
|
object->type = EMPACK_TYPE_FIXSTR;
|
2025-09-20 23:15:04 -05:00
|
|
|
p += object->val.str.size;
|
2025-09-15 01:17:36 -05:00
|
|
|
}
|
|
|
|
|
else if ((object->type >= EMPACK_TYPE_NEG_FIXINT) && (object->type <= EMPACK_NEG_FIXINT_MAX)) {
|
|
|
|
|
object->val.int8 = (int8_t)object->type;
|
|
|
|
|
object->type = EMPACK_TYPE_NEG_FIXINT;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
object->type = EMPACK_TYPE_ERROR;
|
|
|
|
|
ret = EMPACK_STATUS_ERROR;
|
|
|
|
|
goto empack_parse_one_return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
empack_parse_one_return:
|
|
|
|
|
if ((ret == EMPACK_STATUS_EXTRA) && (p == (*len))) {
|
|
|
|
|
ret = EMPACK_STATUS_COMPLETE;
|
|
|
|
|
}
|
|
|
|
|
(*len) = p;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-20 23:15:04 -05:00
|
|
|
uint32_t
|
|
|
|
|
empack_print(empack_t *empack,
|
|
|
|
|
void (*print_func)(const char *buf, uint32_t buflen, void *arg),
|
|
|
|
|
void *arg,
|
|
|
|
|
const char *indent)
|
|
|
|
|
{
|
|
|
|
|
uint32_t ret = 0;
|
|
|
|
|
int indent_depth = 0;
|
|
|
|
|
size_t indent_len = indent ? strlen(indent) : 0;
|
|
|
|
|
empack_obj_t *cur = &empack->root;
|
|
|
|
|
|
|
|
|
|
#define EMPACK_PRINT(buf, len) do { \
|
|
|
|
|
const char *__buf = (buf); \
|
|
|
|
|
uint32_t __len = (len); \
|
|
|
|
|
ret += __len; \
|
|
|
|
|
print_func(__buf, len, arg); \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
#define EMPACK_PRINT_INDENT() do { \
|
|
|
|
|
if (indent) { \
|
|
|
|
|
for (int __i = 0; __i < indent_depth; __i++) { \
|
|
|
|
|
EMPACK_PRINT(indent, indent_len); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define EMPACK_PRINT_NEWLINE() do { \
|
|
|
|
|
if (indent) { \
|
|
|
|
|
EMPACK_PRINT("\r\n", 2); \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
while (cur) {
|
|
|
|
|
/* Large enough for uint64/double */
|
|
|
|
|
char tmp[24];
|
|
|
|
|
int tmp_len;
|
|
|
|
|
|
|
|
|
|
/* Print indent for everything except map value */
|
|
|
|
|
if (cur->parent && EMPACK_IS_MAP(cur->parent->type)) {
|
|
|
|
|
empack_map_t *pmap = &cur->parent->val.map;
|
|
|
|
|
|
|
|
|
|
if (cur == &pmap->pairs[pmap->pairs_parsed].key) {
|
|
|
|
|
EMPACK_PRINT_INDENT();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
EMPACK_PRINT_INDENT();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (cur->type) {
|
|
|
|
|
case EMPACK_TYPE_FIXMAP:
|
|
|
|
|
case EMPACK_TYPE_MAP16:
|
|
|
|
|
case EMPACK_TYPE_MAP32:
|
|
|
|
|
EMPACK_PRINT("{", 1);
|
2025-09-21 20:01:16 -05:00
|
|
|
|
|
|
|
|
if (cur->val.map.pair_count > 0) {
|
|
|
|
|
EMPACK_PRINT_NEWLINE();
|
|
|
|
|
cur->val.map.pairs_parsed = 0;
|
|
|
|
|
indent_depth++;
|
|
|
|
|
} else {
|
|
|
|
|
EMPACK_PRINT("}", 1);
|
|
|
|
|
}
|
2025-09-20 23:15:04 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXARRAY:
|
|
|
|
|
case EMPACK_TYPE_ARRAY16:
|
|
|
|
|
case EMPACK_TYPE_ARRAY32:
|
|
|
|
|
EMPACK_PRINT("[", 1);
|
2025-09-21 20:01:16 -05:00
|
|
|
|
|
|
|
|
if (cur->val.array.object_count > 0) {
|
|
|
|
|
EMPACK_PRINT_NEWLINE();
|
|
|
|
|
cur->val.array.objects_parsed = 0;
|
|
|
|
|
indent_depth++;
|
|
|
|
|
} else {
|
|
|
|
|
EMPACK_PRINT("]", 1);
|
|
|
|
|
}
|
2025-09-20 23:15:04 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_FIXSTR:
|
|
|
|
|
case EMPACK_TYPE_STR8:
|
|
|
|
|
case EMPACK_TYPE_STR16:
|
|
|
|
|
case EMPACK_TYPE_STR32:
|
|
|
|
|
EMPACK_PRINT("\"", 1);
|
|
|
|
|
EMPACK_PRINT(cur->val.str.data, cur->val.str.size);
|
|
|
|
|
EMPACK_PRINT("\"", 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_BIN8:
|
|
|
|
|
case EMPACK_TYPE_BIN16:
|
|
|
|
|
case EMPACK_TYPE_BIN32:
|
|
|
|
|
EMPACK_PRINT("\"", 1);
|
|
|
|
|
for (uint32_t i = 0; i < cur->val.bin.size; i++) {
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%02X", ((uint8_t *)cur->val.bin.data)[i]);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
}
|
|
|
|
|
EMPACK_PRINT("\"", 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_EXT8:
|
|
|
|
|
case EMPACK_TYPE_EXT16:
|
|
|
|
|
case EMPACK_TYPE_EXT32:
|
|
|
|
|
case EMPACK_TYPE_FIXEXT1:
|
|
|
|
|
case EMPACK_TYPE_FIXEXT2:
|
|
|
|
|
case EMPACK_TYPE_FIXEXT4:
|
|
|
|
|
case EMPACK_TYPE_FIXEXT8:
|
|
|
|
|
case EMPACK_TYPE_FIXEXT16:
|
|
|
|
|
EMPACK_PRINT("\"", 1);
|
|
|
|
|
for (uint32_t i = 0; i < cur->val.ext.size; i++) {
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%02X", ((uint8_t *)cur->val.ext.data)[i]);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
}
|
|
|
|
|
EMPACK_PRINT("\"", 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EMPACK_TYPE_NIL:
|
|
|
|
|
EMPACK_PRINT("null", 4);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_ERROR:
|
|
|
|
|
EMPACK_PRINT("ERROR", 5);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_FALSE:
|
|
|
|
|
EMPACK_PRINT("false", 5);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_TRUE:
|
|
|
|
|
EMPACK_PRINT("true", 4);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_FLOAT32:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%f", cur->val.float32);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_FLOAT64:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%f", cur->val.float64);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_POS_FIXINT:
|
|
|
|
|
case EMPACK_TYPE_UINT8:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%u", cur->val.uint8);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_UINT16:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%u", cur->val.uint16);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_UINT32:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%u", cur->val.uint32);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_UINT64:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%u%u",
|
|
|
|
|
(uint32_t)(cur->val.uint64 >> 32),
|
|
|
|
|
(uint32_t)cur->val.uint64);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_NEG_FIXINT:
|
|
|
|
|
case EMPACK_TYPE_INT8:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%d", cur->val.int8);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_INT16:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%d", cur->val.int16);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_INT32:
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%d", cur->val.int32);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
break;
|
|
|
|
|
case EMPACK_TYPE_INT64:
|
|
|
|
|
{
|
|
|
|
|
uint64_t tmp_num;
|
|
|
|
|
const char *sign = "";
|
|
|
|
|
|
|
|
|
|
if (cur->val.int64 < 0) {
|
|
|
|
|
tmp_num = -cur->val.int64;
|
|
|
|
|
sign = "-";
|
|
|
|
|
} else {
|
|
|
|
|
tmp_num = cur->val.int64;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmp_len = snprintf(tmp, sizeof(tmp), "%s%u%u",
|
|
|
|
|
sign,
|
|
|
|
|
(uint32_t)(tmp_num >> 32),
|
|
|
|
|
(uint32_t)tmp_num);
|
|
|
|
|
EMPACK_PRINT(tmp, tmp_len);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cur->parent && EMPACK_IS_MAP(cur->parent->type)) {
|
|
|
|
|
empack_map_t *pmap = &cur->parent->val.map;
|
|
|
|
|
|
|
|
|
|
if (cur == &pmap->pairs[pmap->pairs_parsed].key) {
|
|
|
|
|
EMPACK_PRINT(":", 1);
|
|
|
|
|
if (indent) {
|
|
|
|
|
EMPACK_PRINT(" ", 1);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (pmap->pairs_parsed != (pmap->pair_count - 1)) {
|
|
|
|
|
EMPACK_PRINT(",", 1);
|
|
|
|
|
}
|
|
|
|
|
EMPACK_PRINT_NEWLINE();
|
|
|
|
|
|
|
|
|
|
pmap->pairs_parsed++;
|
|
|
|
|
if (pmap->pairs_parsed == pmap->pair_count) {
|
|
|
|
|
indent_depth--;
|
|
|
|
|
EMPACK_PRINT_INDENT();
|
|
|
|
|
EMPACK_PRINT("}", 1);
|
|
|
|
|
EMPACK_PRINT_NEWLINE();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (cur->parent && EMPACK_IS_ARRAY(cur->parent->type)) {
|
|
|
|
|
empack_array_t *parr = &cur->parent->val.array;
|
|
|
|
|
|
|
|
|
|
if (parr->objects_parsed != (parr->object_count - 1)) {
|
|
|
|
|
EMPACK_PRINT(",", 1);
|
|
|
|
|
}
|
|
|
|
|
EMPACK_PRINT_NEWLINE();
|
|
|
|
|
|
|
|
|
|
parr->objects_parsed++;
|
|
|
|
|
if (parr->objects_parsed == parr->object_count) {
|
|
|
|
|
indent_depth--;
|
|
|
|
|
EMPACK_PRINT_INDENT();
|
|
|
|
|
EMPACK_PRINT("]", 1);
|
|
|
|
|
EMPACK_PRINT_NEWLINE();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur = cur->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-15 01:17:36 -05:00
|
|
|
static void *
|
|
|
|
|
empack_allocate(empack_t *empack, uint32_t size)
|
|
|
|
|
{
|
|
|
|
|
void *ret;
|
|
|
|
|
|
|
|
|
|
if (size > (empack->arena_sz - empack->arena_used)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = &((uint8_t *)empack->arena)[empack->arena_used];
|
|
|
|
|
empack->arena_used += size;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
memswap(uint8_t *dst, const uint8_t *src, uint32_t len)
|
|
|
|
|
{
|
|
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
|
|
|
|
dst[i] = src[len - i - 1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
|
buf_to_u16(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
uint16_t ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 2);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
|
buf_to_u32(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
uint32_t ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 4);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint64_t
|
|
|
|
|
buf_to_u64(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
uint64_t ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 8);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int16_t
|
|
|
|
|
buf_to_i16(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
int16_t ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 2);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t
|
|
|
|
|
buf_to_i32(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
int32_t ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 4);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int64_t
|
|
|
|
|
buf_to_i64(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
int64_t ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 8);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static float
|
|
|
|
|
buf_to_float(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
float ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 4);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
buf_to_double(const uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
double ret;
|
|
|
|
|
memswap((uint8_t *)&ret, buf, 8);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|