]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Lib: mostly rewritten CBOR encoder mq-cbor-encoder-parser
authorMaria Matejka <mq@ucw.cz>
Mon, 7 Oct 2024 13:05:21 +0000 (15:05 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 14 Mar 2025 20:11:37 +0000 (21:11 +0100)
lib/Makefile
lib/cbor.c
lib/cbor.h

index 8d3ec9b44f9c7b184ad7e49ef8f4755348c69827..346971b94387330b3ae61daa7ae1d4888b2e88b4 100644 (file)
@@ -1,4 +1,4 @@
-src := a-path.c a-set.c 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 sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := a-path.c a-set.c 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 sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
 obj := $(src-o-files)
 $(all-daemon)
 
index cdc1be2a2bd198d829bd2878c8a0c86dffe4a4f3..233758ec2e0cf6665085c0e7fef6c284687c69dd 100644 (file)
@@ -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;
+  return w->data.pos + amount <= w->data.end;
 }
-  
-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++;
+
+#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)
+{
+  *(CBOR_PUT(1)) = b;
+  return true;
 }
 
-void cbor_open_list(struct cbor_writer *writer)
+bool cbor_put_raw_u16(struct cbor_writer *w, u16 val)
 {
-  check_memory(writer, 2);
-  writer->cbor[writer->pt] = 0x9f;
-  writer->pt++;
+  put_u16(CBOR_PUT(2), val);
+  return true;
 }
 
-void cbor_close_block_or_list(struct cbor_writer *writer)
+bool cbor_put_raw_u32(struct cbor_writer *w, u32 val)
 {
-  check_memory(writer, 2);
-  writer->cbor[writer->pt] = 0xff;
-  writer->pt++;
+  put_u32(CBOR_PUT(4), val);
+  return true;
+}
+
+bool cbor_put_raw_u64(struct cbor_writer *w, u64 val)
+{
+  put_u64(CBOR_PUT(8), val);
+  return true;
+}
+
+bool cbor_put_raw_data(struct cbor_writer *w, const byte *block, u64 size)
+{
+  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);
 }
 
-void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length)
+bool cbor_put_int(struct cbor_writer *w, int64_t value)
 {
-  write_item(writer, 5, length);
+  if (value >= 0)
+    return cbor_put(w, CBOR_POSINT, value);
+  else
+    return cbor_put(w, CBOR_NEGINT, -1-value);
 }
 
-void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length)
+/* Strings */
+bool cbor_put_raw_bytes(struct cbor_writer *w, enum cbor_basic_type type, const byte *block, u64 size)
 {
-  write_item(writer, 4, length);
+  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);
+}
 
-void cbor_add_int(struct cbor_writer *writer, int64_t item)
+bool cbor_put_close(struct cbor_writer *w, u64 actual_size, bool strict)
 {
-  if (item >= 0)
+  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)
+  {
+    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)
   {
-    write_item(writer, 0, item); // 0 is the "major" (three bits) introducing positive int, 1 is for negative
+    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
index f71ca9fbf7b49b0f86e5d1a53a4d5ff2120292e5..c3d3b32a4ff1b70d96573a87839787e92fe604ff 100644 (file)
@@ -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];
 };
 
-
-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);
-
-
+/* 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;
+}
+
+#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