summaryrefslogtreecommitdiff
path: root/leb128.c
diff options
context:
space:
mode:
Diffstat (limited to 'leb128.c')
-rw-r--r--leb128.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/leb128.c b/leb128.c
new file mode 100644
index 0000000..c1584c5
--- /dev/null
+++ b/leb128.c
@@ -0,0 +1,165 @@
+/*
+ * 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\n", __func__);
+ 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;
+}