Welcome to little lamb

Code » limb » commit 874b52c

Add patrim.h & related functions

author Olivier Brunel
2023-04-30 13:52:14 UTC
committer Olivier Brunel
2023-05-20 18:06:39 UTC
parent 8c6f6b94532cd641ae826d264e88476f256e1005

Add patrim.h & related functions

Our old "data encoding" algorithm based on our u64_pack_trim-ing finally
has a name, patrim.
Introduce for the occasion a couple of helpers to read/write patrim
formated data.

An important change is that IDs are now simply pack-trimmed (instead of
being u16) and the flag for integer/blob is now the LSB.

src/doc/patrim.5.md +41 -0
src/doc/patrim.h.0.md +30 -0
src/doc/patrim.h/patrim_put.3.md +50 -0
src/liblimb/include/limb/patrim.h +16 -0
src/liblimb/patrim.h/patrim_get.c +20 -0
src/liblimb/patrim.h/patrim_put.c +20 -0

diff --git a/src/doc/patrim.5.md b/src/doc/patrim.5.md
new file mode 100644
index 0000000..8eac902
--- /dev/null
+++ b/src/doc/patrim.5.md
@@ -0,0 +1,41 @@
+% limb manual
+% patrim(5)
+
+# NAME
+
+PATRIM - the pack-trimmed format
+
+# DESCRIPTION
+
+The PATRIM format is a simple format that allows to store data in binary form,
+where every data is identified by an ID, that represents either an unsigned
+integer or a blob/byte array.
+
+Data are stored very simply : first the ID, then either the value for an
+integer, or the data length for a blob, in which case said data must immediately
+follow.
+
+IDs and values/lengths are stored using the "pack trimmed" algorithm, as
+described in [u64_pack_trim](3). Meaning the value is stored in little endian
+mode, but only the low 7 bits are used for the value, the most significant bit
+being a flag which, when set, indicates that another byte must be read and
+processed.
+
+Any 64bit number can be written that way, packed into from 1 to 9 bytes,
+depending on the actual value.
+
+The IDs are unsigned numbers to identify their associated value, with the least
+significant bit having a special meaning : if set, it represents a blob,
+otherwise an (unsigned) integer.
+
+That is all.
+
+# FILE FORMATS
+
+As a rule, any file whose content is encoded in PATRIM should first feature an
+header as such :
+
+- A big-endian encoded 32bit magic number, to identify the specific file format.
+  The magic number should have certain bits set to indicate it is PATRIM
+  encoded, specifically : `(magic & 0xf0f0f000) = 0xa0e0f000`
+- A version number, pack-trimmed.
diff --git a/src/doc/patrim.h.0.md b/src/doc/patrim.h.0.md
new file mode 100644
index 0000000..0e7bce8
--- /dev/null
+++ b/src/doc/patrim.h.0.md
@@ -0,0 +1,30 @@
+% limb manual
+% patrim.h(0)
+
+# NAME
+
+patrim.h - encode/decode data in PATRIM format
+
+# SYNOPSIS
+
+    #include <limb/patrim.h>
+
+# DESCRIPTION
+
+The header defines functions used to encode/decode data in [patrim](5) format.
+
+## Functions
+
+The following functions/macros are defined :
+
+: [patrim_isblob](3)
+:: Returns whether the given ID is that of a blob or not.
+
+: [patrim_isint](3)
+:: Returns whether the given ID is that of an integer or not.
+
+: [patrim_put](3)
+:: To encode data in [patrim](5) format.
+
+: [patrim_get](3)
+:: To decode data in [patrim](5) format.
diff --git a/src/doc/patrim.h/patrim_put.3.md b/src/doc/patrim.h/patrim_put.3.md
new file mode 100644
index 0000000..964a262
--- /dev/null
+++ b/src/doc/patrim.h/patrim_put.3.md
@@ -0,0 +1,50 @@
+% limb manual
+% patrim_put(3)
+
+# NAME
+
+patrim\_put, patrim\_get, patrim\isblob, patrim\isint - encode/decode data in
+PATRIM format
+
+# SYNOPSIS
+
+    #include <limb/patrim.h>
+
+```pre hl
+int patrim_put(char *<em>dst</em>, size_t <em>dlen</em>, size_t <em>offset</em>, u64 <em>id</em>, u64 <em>u</em>)
+int patrim_get(u64 *<em>id</em>, u64 *<em>u</em>, const char *<em>data</em>, size_t <em>dlen</em>, size_t <em>offset</em>)
+
+int patrim_isblob(u64 <em>id</em>)
+int patrim_isint(u64 <em>id</em>)
+```
+
+# DESCRIPTION
+
+The `patrim_put`() function will encode into the memory pointed by `dst` of
+length `dlen`, starting at byte `offset`, the data for the given `id` and its
+associated value or length, `u`.
+
+So `u` must be either the value if `id` represents an integer, or the length of
+the blob if `id` represents a blob. The actual data/blob content should
+obviously be added afterwards.
+
+The `patrim_get`() function will read the memory pointed by `data`, starting at
+byte `offset` and not going past `dlen` bytes, decoding PATRIM-encoded data and
+placing the ID in the memory pointed by `id` and either the value of data
+length, depending whether the ID of that of an integer or a blob respectively,
+into the memory pointed by `u`.
+
+The `patrim_isblob`() macro returns 1 if the `id` if that of a blob, zero
+otherwise.
+
+The `patrim_isint`() macro returns 1 if the `id` if that of an integer, zero
+otherwise.
+
+# RETURN VALUE
+
+On success the `patrim_put`() and `patrim_get`() functions return the number of
+bytes written into `dst` or read from `data`, respectively. Otherwise - meaning
+not enough bytes could be written or read - they return -1.
+
+The `patrim_isblob`() and `patrim_isint`() macros return 1 id `id` represents a
+blob or an integer, respectively, otherwise they return 0.
diff --git a/src/liblimb/include/limb/patrim.h b/src/liblimb/include/limb/patrim.h
new file mode 100644
index 0000000..c13cc2a
--- /dev/null
+++ b/src/liblimb/include/limb/patrim.h
@@ -0,0 +1,16 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LIMB_PATRIM_H
+#define LIMB_PATRIM_H
+
+#include <sys/types.h>
+#include <limb/int.h>
+
+#define patrim_isblob(id)       (id & 1)
+#define patrim_isint(id)        !patrim_isblob(id)
+
+extern int patrim_put(char *dst, size_t dlen, size_t offset, u64 id, u64 u);
+extern int patrim_get(u64 *id, u64 *u, const char *data, size_t dlen, size_t offset);
+
+#endif /* LIMB_PATRIM_H */
diff --git a/src/liblimb/patrim.h/patrim_get.c b/src/liblimb/patrim.h/patrim_get.c
new file mode 100644
index 0000000..4cc1175
--- /dev/null
+++ b/src/liblimb/patrim.h/patrim_get.c
@@ -0,0 +1,20 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <limb/patrim.h>
+#include <limb/u64.h>
+
+int
+patrim_get(u64 *id, u64 *u, const char *data, size_t dlen, size_t offset)
+{
+    int r, n;
+
+    if (offset >= dlen) return -1;
+    r = u64_unpack_trim(id, data + offset, dlen - offset);
+    if (r < 0) return -1;
+
+    n = u64_unpack_trim(u, data + offset + r, dlen - offset - r);
+    if (n < 0) return -1;
+
+    return r + n;
+}
diff --git a/src/liblimb/patrim.h/patrim_put.c b/src/liblimb/patrim.h/patrim_put.c
new file mode 100644
index 0000000..d0f24e7
--- /dev/null
+++ b/src/liblimb/patrim.h/patrim_put.c
@@ -0,0 +1,20 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <limb/patrim.h>
+#include <limb/u64.h>
+
+int
+patrim_put(char *dst, size_t dlen, size_t offset, u64 id, u64 u)
+{
+    int r, n;
+
+    if (offset >= dlen) return -1;
+    r = u64_pack_trim(dst + offset, dlen - offset, id);
+    if (r < 0) return -1;
+
+    n = u64_pack_trim(dst + offset + r, dlen - offset - r, u);
+    if (n < 0) return -1;
+
+    return r + n;
+}