summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2024-06-17 00:49:20 +0200
committerLizzy Fleckenstein <lizzy@vlhl.dev>2024-06-17 00:51:45 +0200
commit51598ba379d31998705f4f991d1606053500f942 (patch)
treee208038ebd2c56880920141a24a29f71dc6c005b
parenta3fbea78730b1359146193e0d128668426085cd8 (diff)
implement serialization
Signed-off-by: Lizzy Fleckenstein <lizzy@vlhl.dev>
-rw-r--r--include/ser.h45
-rw-r--r--include/str.h3
-rw-r--r--meson.build1
-rw-r--r--src/ser.c119
4 files changed, 168 insertions, 0 deletions
diff --git a/include/ser.h b/include/ser.h
new file mode 100644
index 0000000..fc3451e
--- /dev/null
+++ b/include/ser.h
@@ -0,0 +1,45 @@
+#ifndef SER_H
+#define SER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "str.h"
+
+// ser
+
+void ser_bytes(strbuf *w, size_t len, uint8_t *x);
+
+void ser_str(strbuf *w, str x);
+
+void ser_u8(strbuf *w, uint8_t x);
+void ser_i8(strbuf *w, int8_t x);
+
+void ser_u16(strbuf *w, uint16_t x);
+void ser_i16(strbuf *w, int16_t x);
+
+void ser_u32(strbuf *w, uint32_t x);
+void ser_i32(strbuf *w, int32_t x);
+
+void ser_u64(strbuf *w, uint64_t x);
+void ser_i64(strbuf *w, int64_t x);
+
+// deser
+
+bool deser_bytes(str *r, size_t len, uint8_t *buf);
+
+bool deser_str(str *r, str *buf); // returns slice!
+
+bool deser_u8(str *r, uint8_t *buf);
+bool deser_i8(str *r, int8_t *buf);
+
+bool deser_u16(str *r, uint16_t *buf);
+bool deser_i16(str *r, int16_t *buf);
+
+bool deser_u32(str *r, uint32_t *buf);
+bool deser_i32(str *r, int32_t *buf);
+
+bool deser_u64(str *r, uint64_t *buf);
+bool deser_i64(str *r, int64_t *buf);
+
+#endif
diff --git a/include/str.h b/include/str.h
index f4054a1..b208515 100644
--- a/include/str.h
+++ b/include/str.h
@@ -19,6 +19,9 @@ typedef array(char) str;
#define S(X) ((str) { len(X)-1, X })
#define NILS ((str) { 0, NULL })
+typedef struct { size_t cap; str buf; } strbuf;
+#define NILSBUF ((strbuf) { 0, NILS })
+
// compares two strings by length and ASCII values. return value:
// < 0 if s1 < s2
// = 0 if s1 = s2
diff --git a/meson.build b/meson.build
index 84bfb78..d959da5 100644
--- a/meson.build
+++ b/meson.build
@@ -9,6 +9,7 @@ server = executable('server',
'src/server.c',
'src/str.c',
'src/peer.c',
+ 'src/ser.c',
],
include_directories: 'include/',
dependencies: [dependency('libpng')],
diff --git a/src/ser.c b/src/ser.c
new file mode 100644
index 0000000..998c81b
--- /dev/null
+++ b/src/ser.c
@@ -0,0 +1,119 @@
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include "ser.h"
+
+void ser_bytes(strbuf *w, size_t len, uint8_t *x)
+{
+ while (w->buf.len + len > w->cap)
+ w->buf.data = realloc(w->buf.data, w->cap = w->cap ? w->cap * 2 : 1);
+ memcpy(w->buf.data, x, len);
+ w->buf.len += len;
+}
+
+void ser_str(strbuf *w, str x)
+{
+ ser_u16(w, x.len);
+ ser_bytes(w, x.len, (uint8_t *) x.data);
+}
+
+void ser_u8(strbuf *w, uint8_t x)
+{
+ ser_bytes(w, 1, &x);
+}
+
+void ser_u16(strbuf *w, uint16_t x)
+{
+ x = htole16(x);
+ ser_bytes(w, 2, (uint8_t *) &x);
+}
+
+void ser_u32(strbuf *w, uint32_t x)
+{
+ x = htole32(x);
+ ser_bytes(w, 4, (uint8_t *) &x);
+}
+
+void ser_u64(strbuf *w, uint64_t x)
+{
+ x = htole64(x);
+ ser_bytes(w, 8, (uint8_t *) &x);
+}
+
+#define SER_SIGN(N) void ser_i##N(strbuf *w, int##N##_t x) { ser_u##N(w, x); };
+
+SER_SIGN(16)
+SER_SIGN(32)
+SER_SIGN(64)
+
+#undef SER_SIGN
+
+bool deser_bytes(str *r, size_t len, uint8_t *buf)
+{
+ if (len > r->len)
+ return false;
+
+ memcpy(buf, r->data, len);
+ *r = str_advance(*r, len);
+ return true;
+}
+
+bool deser_str(str *r, str *buf)
+{
+ uint16_t len;
+ if (!deser_u16(r, &len))
+ return false;
+
+ if (len > r->len)
+ return false;
+
+ *buf = (str) { len, r->data };
+ *r = str_advance(*r, len);
+ return true;
+}
+
+bool deser_u8(str *r, uint8_t *buf)
+{
+ return deser_bytes(r, 1, buf);
+}
+
+bool deser_u16(str *r, uint16_t *buf)
+{
+ if (!deser_bytes(r, 2, (uint8_t *) buf))
+ return false;
+ *buf = le16toh(*buf);
+ return true;
+}
+
+bool deser_u32(str *r, uint32_t *buf)
+{
+ if (!deser_bytes(r, 4, (uint8_t *) buf))
+ return false;
+ *buf = le32toh(*buf);
+ return true;
+}
+
+bool deser_u64(str *r, uint64_t *buf)
+{
+ if (!deser_bytes(r, 8, (uint8_t *) buf))
+ return false;
+ *buf = le64toh(*buf);
+ return true;
+}
+
+#define DESER_SIGN(N) \
+ bool deser_i##N(str *r, int##N##_t *buf) \
+ { \
+ uint##N##_t x; \
+ if (!deser_u##N(r, &x)) \
+ return false; \
+ *buf = x; \
+ return true; \
+ }
+
+DESER_SIGN(8)
+DESER_SIGN(16)
+DESER_SIGN(32)
+DESER_SIGN(64)
+
+#undef DESER_SIGN