File syn_cbor_read.c¶
File List > src > syntropic > util > syn_cbor_read.c
Go to the documentation of this file
#if __has_include("syn_config.h")
#include "syn_config.h"
#endif
#if !defined(SYN_USE_CBOR) || SYN_USE_CBOR
#include "syn_cbor_read.h"
#include <string.h>
static uint8_t consume_byte(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return 0u;
}
return r->buf[r->pos++];
}
static uint8_t peek_byte(const SYN_CborReader *r)
{
if (r->pos >= r->len)
return 0u;
return r->buf[r->pos];
}
static uint64_t decode_arg(SYN_CborReader *r, uint8_t info)
{
if (info <= 23u) {
return (uint64_t)info;
}
switch (info) {
case 24u:
return (uint64_t)consume_byte(r);
case 25u: {
uint64_t hi = consume_byte(r);
uint64_t lo = consume_byte(r);
return (hi << 8u) | lo;
}
case 26u: {
uint64_t b3 = consume_byte(r);
uint64_t b2 = consume_byte(r);
uint64_t b1 = consume_byte(r);
uint64_t b0 = consume_byte(r);
return (b3 << 24u) | (b2 << 16u) | (b1 << 8u) | b0;
}
case 27u: {
uint64_t v = 0u;
uint8_t i;
for (i = 0u; i < 8u; i++) {
v = (v << 8u) | (uint64_t)consume_byte(r);
}
return v;
}
default:
r->ok = false;
return 0u;
}
}
void syn_cbor_reader_init(SYN_CborReader *r, const uint8_t *buf, size_t len)
{
r->buf = buf;
r->len = len;
r->pos = 0u;
r->ok = true;
}
SYN_CborType syn_cbor_peek_type(const SYN_CborReader *r)
{
if (r->pos >= r->len)
return SYN_CBOR_ERROR;
uint8_t b = peek_byte(r);
uint8_t major = b >> 5u;
uint8_t info = b & 0x1Fu;
if (major <= 5u) {
return (SYN_CborType)major;
}
/* Major type 7: distinguish float, bool, null */
if (info == 20u || info == 21u)
return SYN_CBOR_BOOL;
if (info == 22u)
return SYN_CBOR_NULL;
if (info == 25u || info == 26u || info == 27u)
return SYN_CBOR_FLOAT;
return SYN_CBOR_ERROR;
}
#define SKIP_MAX_DEPTH 8u
void syn_cbor_skip(SYN_CborReader *r)
{
size_t pending[SKIP_MAX_DEPTH]; /* remaining items at each depth */
uint8_t depth = 0u;
pending[0] = 1u; /* we must skip exactly 1 top-level item */
while (depth < SKIP_MAX_DEPTH && pending[depth] > 0u) {
pending[depth]--;
if (r->pos >= r->len) {
r->ok = false;
return;
}
uint8_t b = consume_byte(r);
uint8_t major = b >> 5u;
uint8_t info = b & 0x1Fu;
if (major == 7u) {
/* float32: 4 more bytes; float16: 2; float64: 8; else 0 */
size_t skip_bytes = 0;
if (info == 25u) {
skip_bytes = 2u;
} else if (info == 26u) {
skip_bytes = 4u;
} else if (info == 27u) {
skip_bytes = 8u;
}
if (skip_bytes > 0) {
if (r->len - r->pos < skip_bytes) {
r->ok = false;
return;
}
r->pos += skip_bytes;
}
/* bool/null/simple: 0 extra bytes */
} else if (major == 2u || major == 3u) {
/* byte/text string: skip 'arg' data bytes */
uint64_t n = decode_arg(r, info);
if (!r->ok || (size_t)n > (r->len - r->pos)) {
r->ok = false;
return;
}
r->pos += (size_t)n;
} else if (major == 4u) {
/* array: push 'arg' items */
uint64_t n = decode_arg(r, info);
depth++;
if (depth >= SKIP_MAX_DEPTH) {
r->ok = false;
return;
}
pending[depth] = (size_t)n;
} else if (major == 5u) {
/* map: push 'arg * 2' items (each pair = key + value) */
uint64_t n = decode_arg(r, info);
depth++;
if (depth >= SKIP_MAX_DEPTH) {
r->ok = false;
return;
}
pending[depth] = (size_t)(n * 2u);
} else {
/* major type 0 or 1: uint/int, arg is the value, no data bytes */
decode_arg(r, info);
}
/* Pop completed levels */
while (depth > 0u && pending[depth] == 0u) {
depth--;
}
}
#undef SKIP_MAX_DEPTH
}
/* ── Collections ─────────────────────────────────────────────────────────── */
size_t syn_cbor_read_map_begin(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return 0u;
}
uint8_t b = consume_byte(r);
if ((b >> 5u) != 5u) {
r->ok = false;
return 0u;
}
return (size_t)decode_arg(r, b & 0x1Fu);
}
size_t syn_cbor_read_array_begin(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return 0u;
}
uint8_t b = consume_byte(r);
if ((b >> 5u) != 4u) {
r->ok = false;
return 0u;
}
return (size_t)decode_arg(r, b & 0x1Fu);
}
/* ── Scalars ─────────────────────────────────────────────────────────────── */
uint64_t syn_cbor_read_uint(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return 0u;
}
uint8_t b = consume_byte(r);
if ((b >> 5u) != 0u) {
r->ok = false;
return 0u;
}
return decode_arg(r, b & 0x1Fu);
}
int64_t syn_cbor_read_int(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return 0;
}
uint8_t b = consume_byte(r);
uint8_t major = b >> 5u;
uint8_t info = b & 0x1Fu;
if (major == 0u) {
return (int64_t)decode_arg(r, info);
}
if (major == 1u) {
return (int64_t)(-1 - (int64_t)decode_arg(r, info));
}
r->ok = false;
return 0;
}
float syn_cbor_read_float(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return 0.0f;
}
uint8_t b = consume_byte(r);
/* Must be major type 7, info=26 (float32) */
if (b != 0xFAu) {
r->ok = false;
return 0.0f;
}
uint32_t bits = 0u;
bits |= (uint32_t)consume_byte(r) << 24u;
bits |= (uint32_t)consume_byte(r) << 16u;
bits |= (uint32_t)consume_byte(r) << 8u;
bits |= (uint32_t)consume_byte(r);
if (!r->ok) {
return 0.0f;
}
float v = 0.0f;
memcpy(&v, &bits, sizeof(v));
return v;
}
bool syn_cbor_read_bool(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return false;
}
uint8_t b = consume_byte(r);
if (b == 0xF5u)
return true;
if (b == 0xF4u)
return false;
r->ok = false;
return false;
}
void syn_cbor_read_null(SYN_CborReader *r)
{
if (r->pos >= r->len) {
r->ok = false;
return;
}
uint8_t b = consume_byte(r);
if (b != 0xF6u) {
r->ok = false;
}
}
/* ── Strings ─────────────────────────────────────────────────────────────── */
size_t syn_cbor_read_text(SYN_CborReader *r, char *buf, size_t cap)
{
if (r->pos >= r->len) {
r->ok = false;
return 0u;
}
uint8_t b = consume_byte(r);
if ((b >> 5u) != 3u) {
r->ok = false;
return 0u;
}
size_t n = (size_t)decode_arg(r, b & 0x1Fu);
size_t available = (r->pos < r->len) ? (r->len - r->pos) : 0u;
if (n > available) {
r->ok = false;
}
size_t copy = (n < cap) ? n : (cap > 0u ? cap - 1u : 0u);
if (copy > available) {
copy = available;
}
if (buf != NULL && cap > 0u) {
if (copy > 0u) {
memcpy(buf, r->buf + r->pos, copy);
}
buf[copy] = '\0';
}
if (n <= available) {
r->pos += n;
} else {
r->pos = r->len;
r->ok = false;
}
return n;
}
size_t syn_cbor_read_bytes(SYN_CborReader *r, uint8_t *buf, size_t cap)
{
if (r->pos >= r->len) {
r->ok = false;
return 0u;
}
uint8_t b = consume_byte(r);
if ((b >> 5u) != 2u) {
r->ok = false;
return 0u;
}
size_t n = (size_t)decode_arg(r, b & 0x1Fu);
size_t available = (r->pos < r->len) ? (r->len - r->pos) : 0u;
if (n > available) {
r->ok = false;
}
size_t copy = (n < cap) ? n : cap;
if (copy > available) {
copy = available;
}
if (buf != NULL && copy > 0u) {
memcpy(buf, r->buf + r->pos, copy);
}
if (n <= available) {
r->pos += n;
} else {
r->pos = r->len;
r->ok = false;
}
return n;
}
#endif /* SYN_USE_CBOR */