aboutsummaryrefslogtreecommitdiff
path: root/leb128.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2025-03-06 16:37:12 +0100
committerXavier Del Campo Romero <xavi92@disroot.org>2025-11-07 09:55:58 +0100
commit0086ccf0272fa195dca36845fde9c54149c72f0e (patch)
treedc025e30b7e0a6830e44c9558f3b800295cc79df /leb128.c
downloadnwc-0086ccf0272fa195dca36845fde9c54149c72f0e.tar.gz
First commit
Diffstat (limited to 'leb128.c')
-rw-r--r--leb128.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/leb128.c b/leb128.c
new file mode 100644
index 0000000..45a9611
--- /dev/null
+++ b/leb128.c
@@ -0,0 +1,211 @@
+/*
+ * nwc, a NanoWasm compiler
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Adapted from:
+ *
+ * nanowasm, a tiny WebAssembly/Wasm interpreter
+ * Copyright (C) 2023-2024 Xavier Del Campo Romero
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * Which, in turn, was adapted from the wac project:
+ * https://github.com/kanaka/wac
+ *
+ * Copyright (C) Joel Martin <github@martintribe.org>
+ * The wac project is licensed under the MPL 2.0 (Mozilla Public License
+ * 2.0). The text of the MPL 2.0 license is included below and can be
+ * found at https://www.mozilla.org/MPL/2.0/
+ */
+
+#include "types.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+static int read_leb128(FILE *const f, const unsigned maxbits, const bool sign,
+ unsigned long long *const out)
+{
+ uint8_t byte;
+ unsigned long long result = 0;
+ unsigned shift = 0, bcnt = 0;
+
+ for (;;)
+ {
+ if (!fread(&byte, sizeof byte, 1, f))
+ {
+ if (ferror(f))
+ fprintf(stderr, "%s: ferror\n", __func__);
+
+ return -1;
+ }
+
+ result |= (unsigned long long)(byte & 0x7f) << shift;
+ shift += 7;
+
+ if (!(byte & 0x80))
+ break;
+ else if (++bcnt > (maxbits + 7u - 1u) / 7u)
+ {
+ fprintf(stderr, "%s: overflow, offset=%#lx\n", __func__, ftell(f));
+ return -1;
+ }
+ }
+
+ if (sign && (shift < maxbits) && (byte & 0x40))
+ result |= -1ll << shift;
+
+ *out = result;
+ return 0;
+}
+
+int read_varint1(FILE *const f, varint1 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 1, true, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varint7(FILE *const f, varint7 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 7, true, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varint32(FILE *const f, varint32 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 32, true, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varint64(FILE *const f, varint64 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 64, true, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varuint1(FILE *const f, varuint1 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 1, false, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varuint7(FILE *const f, varuint7 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 7, false, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varuint32(FILE *const f, varuint32 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 32, false, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+int read_varuint64(FILE *const f, varuint64 *const out)
+{
+ unsigned long long res;
+
+ if (read_leb128(f, 64, false, &res))
+ return -1;
+
+ *out = res;
+ return 0;
+}
+
+static int write_uleb128(FILE *const f, unsigned long long v,
+ size_t *const written)
+{
+ size_t w = 0;
+
+ do
+ {
+ uint8_t byte = v & 0x7f;
+
+ if ((v >>= 7))
+ byte |= 0x80;
+
+ if (f && !fwrite(&byte, sizeof byte, 1, f))
+ {
+ fprintf(stderr, "%s: fwrite(3) failed, ferror(3)=%d, feof(3)=%d\n",
+ __func__, ferror(f), feof(f));
+ return -1;
+ }
+
+ w++;
+ } while (v);
+
+ if (written)
+ *written = w;
+
+ return 0;
+}
+
+int write_varuint7(FILE *const f, const varuint7 v)
+{
+ return write_uleb128(f, v, NULL);
+}
+
+int write_varuint32(FILE *const f, const varuint32 v)
+{
+ return write_uleb128(f, v, NULL);
+}
+
+size_t len_varuint32(const varuint32 v)
+{
+ size_t ret;
+
+ write_uleb128(NULL, v, &ret);
+ return ret;
+}