==> include/wasm/leb128.h <==1/* @ajax/wasm-leb128: LEB128 as the WebAssembly binary format defines it (spec 5.2.2).
2 *
3 * Each reader decodes one number from [p, end) and returns the bytes it used, or 0 when the
4 * encoding is truncated, longer than ceil(N / 7) bytes, or its last byte has bits that don't fit
5 * N bits (unsigned: must be zero; signed: must repeat the sign). Freestanding, header-only. */
6#ifndef WASM_LEB128_H
7#define WASM_LEB128_H
8
9#include <stddef.h>
10#include <stdint.h>
11
12/* Unsigned, at most bits (1..64) bits. */
13static inline size_t wasm_leb_unsigned(const uint8_t *p, const uint8_t *end, unsigned bits, uint64_t *out) {
14 uint64_t v = 0;
15 unsigned shift = 0;
16 size_t max = (bits + 6) / 7;
17 for (size_t i = 0; i < max; i++) {
18 if (p + i >= end) return 0;
19 uint8_t b = p[i];
20 if (i == max - 1) {
21 /* The last byte may only hold the bits left. */
22 unsigned left = bits - shift;
23 if (b & 0x80) return 0;
24 if (left < 7 && (b >> left) != 0) return 0;
25 }
26 v |= (uint64_t)(b & 0x7f) << shift;
27 shift += 7;
28 if (!(b & 0x80)) {
29 *out = v;
30 return i + 1;
31 }
32 }
33 return 0;
34}
35
36/* Signed, at most bits (1..64) bits, sign-extended to 64. */
37static inline size_t wasm_leb_signed(const uint8_t *p, const uint8_t *end, unsigned bits, int64_t *out) {
38 uint64_t v = 0;
39 unsigned shift = 0;
40 size_t max = (bits + 6) / 7;
41 for (size_t i = 0; i < max; i++) {
42 if (p + i >= end) return 0;
43 uint8_t b = p[i];
44 if (i == max - 1) {
45 if (b & 0x80) return 0;
46 /* The unused high bits of the last byte must all equal the sign bit of the value. */
47 unsigned left = bits - shift; /* 1..7 value bits in this byte */
48 if (left < 7) {
49 uint8_t sign = (uint8_t)((b >> (left - 1)) & 1);
50 uint8_t rest = (uint8_t)((b & 0x7f) >> left);
51 uint8_t want = sign ? (uint8_t)(0x7f >> left) : 0;
52 if (rest != want) return 0;
53 }
54 }
55 v |= (uint64_t)(b & 0x7f) << shift;
56 shift += 7;
57 if (!(b & 0x80)) {
58 if (shift < 64 && (b & 0x40)) v |= ~(uint64_t)0 << shift;
59 *out = (int64_t)v;
60 return i + 1;
61 }
62 }
63 return 0;
64}
65
66static inline size_t wasm_leb_u32(const uint8_t *p, const uint8_t *end, uint32_t *out) {
67 uint64_t v;
68 size_t n = wasm_leb_unsigned(p, end, 32, &v);
69 if (n) *out = (uint32_t)v;
70 return n;
71}
72
73static inline size_t wasm_leb_u64(const uint8_t *p, const uint8_t *end, uint64_t *out) {
74 return wasm_leb_unsigned(p, end, 64, out);
75}
76
77static inline size_t wasm_leb_s32(const uint8_t *p, const uint8_t *end, int32_t *out) {
78 int64_t v;
79 size_t n = wasm_leb_signed(p, end, 32, &v);
80 if (n) *out = (int32_t)v;
81 return n;
82}
83
84/* Block types are s33. */
85static inline size_t wasm_leb_s33(const uint8_t *p, const uint8_t *end, int64_t *out) {
86 return wasm_leb_signed(p, end, 33, out);
87}
88
89static inline size_t wasm_leb_s64(const uint8_t *p, const uint8_t *end, int64_t *out) {
90 return wasm_leb_signed(p, end, 64, out);
91}
92
93#endif