mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Lib: mostly rewritten CBOR encoder
This commit is contained in:
parent
139355e7ab
commit
ccfc127505
@ -1,4 +1,4 @@
|
||||
src := bitmap.c bitops.c blake2s.c blake2b.c cbor.c cbor-parser.c cbor_parse_tools.c cbor_shortcuts.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
|
||||
src := bitmap.c bitops.c blake2s.c blake2b.c cbor.c cbor-parser.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
|
||||
obj := $(src-o-files)
|
||||
$(all-lib)
|
||||
|
||||
|
183
lib/cbor.c
183
lib/cbor.c
@ -3,6 +3,7 @@
|
||||
|
||||
#include "lib/cbor.h"
|
||||
|
||||
/* String versions of type constants */
|
||||
static const char *cbor_type_str_a[] = {
|
||||
"POSINT",
|
||||
"NEGINT",
|
||||
@ -22,62 +23,179 @@ cbor_type_str(enum cbor_basic_type t)
|
||||
tmp_sprintf("(unknown: %u)", t);
|
||||
}
|
||||
|
||||
void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
|
||||
void check_memory(struct cbor_writer *writer, int add_size);
|
||||
/* Raw data writing */
|
||||
|
||||
struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp)
|
||||
bool cbor_put_check(struct cbor_writer *w, u64 amount)
|
||||
{
|
||||
struct cbor_writer *writer = (struct cbor_writer*)lp_alloc(lp, sizeof(struct cbor_writer));
|
||||
writer->cbor = buff;
|
||||
writer->capacity = capacity;
|
||||
writer->pt = 0;
|
||||
writer->lp = lp;
|
||||
return writer;
|
||||
}
|
||||
|
||||
void cbor_open_block(struct cbor_writer *writer) { // We will need to close the block later manualy
|
||||
check_memory(writer, 2);
|
||||
writer->cbor[writer->pt] = 0xbf;
|
||||
writer->pt++;
|
||||
return w->data.pos + amount <= w->data.end;
|
||||
}
|
||||
|
||||
void cbor_open_list(struct cbor_writer *writer)
|
||||
#define CBOR_PUT(amount) ({ \
|
||||
byte *put = w->data.pos; \
|
||||
if ((w->data.pos += (amount)) >= w->data.end) return false; \
|
||||
put; })
|
||||
|
||||
bool cbor_put_raw_u8(struct cbor_writer *w, byte b)
|
||||
{
|
||||
check_memory(writer, 2);
|
||||
writer->cbor[writer->pt] = 0x9f;
|
||||
writer->pt++;
|
||||
*(CBOR_PUT(1)) = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
void cbor_close_block_or_list(struct cbor_writer *writer)
|
||||
bool cbor_put_raw_u16(struct cbor_writer *w, u16 val)
|
||||
{
|
||||
check_memory(writer, 2);
|
||||
writer->cbor[writer->pt] = 0xff;
|
||||
writer->pt++;
|
||||
put_u16(CBOR_PUT(2), val);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length)
|
||||
bool cbor_put_raw_u32(struct cbor_writer *w, u32 val)
|
||||
{
|
||||
write_item(writer, 5, length);
|
||||
put_u32(CBOR_PUT(4), val);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length)
|
||||
bool cbor_put_raw_u64(struct cbor_writer *w, u64 val)
|
||||
{
|
||||
write_item(writer, 4, length);
|
||||
put_u64(CBOR_PUT(8), val);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void cbor_add_int(struct cbor_writer *writer, int64_t item)
|
||||
bool cbor_put_raw_data(struct cbor_writer *w, const byte *block, u64 size)
|
||||
{
|
||||
if (item >= 0)
|
||||
memcpy(CBOR_PUT(size), block, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Basic value putting */
|
||||
bool cbor_put(struct cbor_writer *w, enum cbor_basic_type type, u64 value)
|
||||
{
|
||||
ASSERT_DIE((type >= 0) && (type <= 8));
|
||||
w->stack[w->stack_pos].items++;
|
||||
byte tt = type << 5;
|
||||
if (value < 0x18)
|
||||
return
|
||||
cbor_put_raw_u8(w, tt | value);
|
||||
else if (value < 0x100)
|
||||
return
|
||||
cbor_put_raw_u8(w, tt | 0x18) &&
|
||||
cbor_put_raw_u8(w, value);
|
||||
else if (value < 0x10000)
|
||||
return
|
||||
cbor_put_raw_u8(w, tt | 0x19) &&
|
||||
cbor_put_raw_u16(w, value);
|
||||
else if (value < 0x100000000)
|
||||
return
|
||||
cbor_put_raw_u8(w, tt | 0x1a) &&
|
||||
cbor_put_raw_u32(w, value);
|
||||
else
|
||||
return
|
||||
cbor_put_raw_u8(w, tt | 0x1b) &&
|
||||
cbor_put_raw_u64(w, value);
|
||||
}
|
||||
|
||||
bool cbor_put_int(struct cbor_writer *w, int64_t value)
|
||||
{
|
||||
if (value >= 0)
|
||||
return cbor_put(w, CBOR_POSINT, value);
|
||||
else
|
||||
return cbor_put(w, CBOR_NEGINT, -1-value);
|
||||
}
|
||||
|
||||
/* Strings */
|
||||
bool cbor_put_raw_bytes(struct cbor_writer *w, enum cbor_basic_type type, const byte *block, u64 size)
|
||||
{
|
||||
return
|
||||
cbor_put(w, type, size) &&
|
||||
cbor_put_raw_data(w, block, size);
|
||||
}
|
||||
|
||||
/* Arrays and maps */
|
||||
bool cbor_put_open(struct cbor_writer *w, enum cbor_basic_type type)
|
||||
{
|
||||
if (++w->stack_pos >= w->stack_max)
|
||||
return false;
|
||||
|
||||
w->stack[w->stack_pos].head = w->data.pos;
|
||||
w->stack[w->stack_pos].items = 0;
|
||||
|
||||
return cbor_put(w, type, ~0ULL);
|
||||
}
|
||||
|
||||
bool cbor_put_close(struct cbor_writer *w, u64 actual_size, bool strict)
|
||||
{
|
||||
ASSERT_DIE(w->stack_pos > 0);
|
||||
|
||||
/* Pop the stack */
|
||||
byte *head = w->stack[w->stack_pos].head;
|
||||
u64 items = w->stack[w->stack_pos].items;
|
||||
|
||||
w->stack_pos--;
|
||||
|
||||
/* Check the original head position */
|
||||
ASSERT_DIE((head[0] & 0x1f) == 0x1f);
|
||||
ASSERT_DIE(w->data.pos >= w->data.start + 9);
|
||||
switch (head[0] >> 5)
|
||||
{
|
||||
write_item(writer, 0, item); // 0 is the "major" (three bits) introducing positive int, 1 is for negative
|
||||
case CBOR_ARRAY:
|
||||
if (strict && (items != actual_size))
|
||||
bug("Inconsistent array item count");
|
||||
break;
|
||||
|
||||
case CBOR_MAP:
|
||||
if (strict && (items != actual_size * 2))
|
||||
bug("Inconsistent map item count");
|
||||
else if (items & 1)
|
||||
bug("Trailing map key");
|
||||
else
|
||||
items /= 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Head points to something other than array or map");
|
||||
}
|
||||
|
||||
/* Move the data back */
|
||||
|
||||
if (items < 0x18)
|
||||
{
|
||||
memmove(head+1, head+9, w->data.pos - (head+9));
|
||||
head[0] &= (0xe0 | items);
|
||||
w->data.pos -= 8;
|
||||
}
|
||||
else if (items < 0x100)
|
||||
{
|
||||
memmove(head+2, head+9, w->data.pos - (head+9));
|
||||
head[0] &= 0xf8;
|
||||
head[1] = items;
|
||||
w->data.pos -= 7;
|
||||
}
|
||||
else if (items < 0x10000)
|
||||
{
|
||||
memmove(head+3, head+9, w->data.pos - (head+9));
|
||||
head[0] &= 0xf9;
|
||||
put_u16(head+1, items);
|
||||
w->data.pos -= 6;
|
||||
}
|
||||
else if (items < 0x100000000)
|
||||
{
|
||||
memmove(head+5, head+9, w->data.pos - (head+9));
|
||||
head[0] &= 0xfa;
|
||||
put_u32(head+1, items);
|
||||
w->data.pos -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_item(writer, 1, -item - 1);
|
||||
head[0] &= 0xfb;
|
||||
put_u64(head+1, items);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Tags: TODO! */
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift)
|
||||
{
|
||||
write_item(writer, 6, 1); // 6 is TAG, 1 is tag number for epoch time
|
||||
@ -253,3 +371,4 @@ void check_memory(struct cbor_writer *writer, int add_size)
|
||||
bug("There is not enough space for cbor response in given buffer");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
86
lib/cbor.h
86
lib/cbor.h
@ -3,6 +3,10 @@
|
||||
|
||||
#include "nest/bird.h"
|
||||
|
||||
/**
|
||||
* CBOR Commonalities
|
||||
**/
|
||||
|
||||
enum cbor_basic_type {
|
||||
CBOR_POSINT = 0,
|
||||
CBOR_NEGINT = 1,
|
||||
@ -16,27 +20,78 @@ enum cbor_basic_type {
|
||||
|
||||
const char *cbor_type_str(enum cbor_basic_type);
|
||||
|
||||
/**
|
||||
* CBOR Writer
|
||||
**/
|
||||
|
||||
struct cbor_writer {
|
||||
int pt; // where will next byte go
|
||||
int capacity;
|
||||
int8_t *cbor;
|
||||
struct linpool *lp;
|
||||
buffer data;
|
||||
uint stack_pos, stack_max; /* Nesting of CBOR_ARRAY / CBOR_MAP */
|
||||
struct cbor_writer_stack_item {
|
||||
u64 items;
|
||||
byte *head;
|
||||
} stack[0];
|
||||
};
|
||||
|
||||
/* Initialization */
|
||||
static inline struct cbor_writer *cbor_writer_init(struct cbor_writer *w, uint stack_max_depth, byte *buf, uint size)
|
||||
{
|
||||
*w = (struct cbor_writer) {
|
||||
.data = {
|
||||
.start = buf,
|
||||
.pos = buf,
|
||||
.end = buf + size,
|
||||
},
|
||||
.stack_max = stack_max_depth,
|
||||
};
|
||||
return w;
|
||||
}
|
||||
|
||||
struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp);
|
||||
|
||||
void cbor_open_block(struct cbor_writer *writer);
|
||||
|
||||
void cbor_open_list(struct cbor_writer *writer);
|
||||
|
||||
void cbor_close_block_or_list(struct cbor_writer *writer);
|
||||
|
||||
void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length);
|
||||
|
||||
void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length);
|
||||
#define cbor_writer_new(p, smax, buf, size) cbor_writer_init(mb_alloc((p), sizeof(struct cbor_writer) + (smax) * sizeof(struct cbor_writer_stack_item)), (smax), (buf), (size))
|
||||
|
||||
|
||||
/* Return how many items have been encoded */
|
||||
static inline int cbor_writer_done(struct cbor_writer *w)
|
||||
{
|
||||
if (w->stack_pos > 0)
|
||||
return -1;
|
||||
else
|
||||
return w->stack[0].items;
|
||||
}
|
||||
|
||||
/* Integer types */
|
||||
bool cbor_put(struct cbor_writer *w, enum cbor_basic_type type, u64 value);
|
||||
#define cbor_put_posint(w,v) cbor_put((w), CBOR_POSINT, (v))
|
||||
#define cbor_put_negint(w,v) cbor_put((w), CBOR_NEGINT, -1-(v))
|
||||
bool cbor_put_int(struct cbor_writer *w, int64_t value);
|
||||
|
||||
/* String types */
|
||||
bool cbor_put_raw_bytes(struct cbor_writer *w, enum cbor_basic_type type, const byte *block, u64 size);
|
||||
#define cbor_put_bytes(w, b, s) cbor_put_raw_bytes((w), CBOR_BYTES, (b), (s))
|
||||
#define cbor_put_text(w, b, s) cbor_put_raw_bytes((w), CBOR_TEXT, (b), (s))
|
||||
#define cbor_put_string(w, s) cbor_put_raw_bytes((w), CBOR_TEXT, (s), strlen(s))
|
||||
#define cbor_put_toks(w, s) cbor_put_raw_bytes((w), CBOR_TEXT, #s, sizeof #s)
|
||||
|
||||
/* Compound types */
|
||||
bool cbor_put_open(struct cbor_writer *w, enum cbor_basic_type type);
|
||||
bool cbor_put_close(struct cbor_writer *w, u64 actual_size, bool strict);
|
||||
#define cbor_open_array(w) cbor_put_open((w), CBOR_ARRAY)
|
||||
#define cbor_open_map(w) cbor_put_open((w), CBOR_MAP)
|
||||
|
||||
#define cbor_close_array(w) cbor_put_close((w), 0, 0)
|
||||
#define cbor_close_map(w) cbor_put_close((w), 0, 0)
|
||||
|
||||
#define CBOR_PUT_ARRAY(w) for (struct cbor_writer *_w = w, *_ww = cbor_open_array(_w) ? (_w) : (bug("buffer overflow on CBOR_ARRAY"), NULL); (_w = NULL), _ww; cbor_close_array(_ww), _ww = NULL)
|
||||
|
||||
#define CBOR_PUT_MAP(w) for (struct cbor_writer *_w = w, *_ww = cbor_open_map(_w) ? (_w) : (bug("buffer overflow on CBOR_MAP"), NULL); (_w = NULL), _ww; cbor_close_map(_ww), _ww = NULL)
|
||||
|
||||
/* Specials */
|
||||
#define cbor_put_false(w) cbor_put((w), CBOR_SPECIAL, 20);
|
||||
#define cbor_put_true(w) cbor_put((w), CBOR_SPECIAL, 21);
|
||||
#define cbor_put_null(w) cbor_put((w), CBOR_SPECIAL, 22);
|
||||
#define cbor_put_undef(w) cbor_put((w), CBOR_SPECIAL, 23);
|
||||
|
||||
#if 0
|
||||
void cbor_add_int(struct cbor_writer *writer, int64_t item);
|
||||
|
||||
void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr);
|
||||
@ -66,6 +121,7 @@ void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
|
||||
void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num);
|
||||
|
||||
void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parser bits
|
||||
|
Loading…
Reference in New Issue
Block a user