master
1#ifndef INPUT_STREAM_H
2#define INPUT_STREAM_H
3
4#include "panic.h"
5#include "wasm.h"
6
7#include <assert.h>
8#include <stdbool.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <stddef.h>
14
15struct InputStream {
16 FILE *stream;
17};
18
19static void InputStream_open(struct InputStream *self, const char *path) {
20 self->stream = fopen(path, "rb");
21 if (self->stream == NULL) panic("unable to open input file");
22}
23
24static void InputStream_close(struct InputStream *self) {
25 fclose(self->stream);
26}
27
28static bool InputStream_atEnd(struct InputStream *self) {
29 return feof(self->stream) != 0;
30}
31
32static uint8_t InputStream_readByte(struct InputStream *self) {
33 int value;
34 value = fgetc(self->stream);
35 if (value == EOF) panic("unexpected end of input stream");
36 return value;
37}
38
39static uint32_t InputStream_readLittle_u32(struct InputStream *self) {
40 uint32_t value = 0;
41 value |= (uint32_t)InputStream_readByte(self) << 0;
42 value |= (uint32_t)InputStream_readByte(self) << 8;
43 value |= (uint32_t)InputStream_readByte(self) << 16;
44 value |= (uint32_t)InputStream_readByte(self) << 24;
45 return value;
46}
47
48static uint64_t InputStream_readLittle_u64(struct InputStream *self) {
49 uint64_t value = 0;
50 value |= (uint64_t)InputStream_readByte(self) << 0;
51 value |= (uint64_t)InputStream_readByte(self) << 8;
52 value |= (uint64_t)InputStream_readByte(self) << 16;
53 value |= (uint64_t)InputStream_readByte(self) << 24;
54 value |= (uint64_t)InputStream_readByte(self) << 32;
55 value |= (uint64_t)InputStream_readByte(self) << 40;
56 value |= (uint64_t)InputStream_readByte(self) << 48;
57 value |= (uint64_t)InputStream_readByte(self) << 56;
58 return value;
59}
60
61static float InputStream_readLittle_f32(struct InputStream *self) {
62 uint32_t value = InputStream_readLittle_u32(self);
63 float result;
64 memcpy(&result, &value, sizeof(result));
65 return result;
66}
67
68static double InputStream_readLittle_f64(struct InputStream *self) {
69 uint64_t value = InputStream_readLittle_u64(self);
70 double result;
71 memcpy(&result, &value, sizeof(result));
72 return result;
73}
74
75static uint32_t InputStream_readLeb128_u32(struct InputStream *self) {
76 uint32_t value = 0;
77 uint8_t shift = 0;
78 uint8_t byte;
79 do {
80 byte = InputStream_readByte(self);
81 assert(shift < 32);
82 value |= (uint32_t)(byte & 0x7F) << shift;
83 shift += 7;
84 } while (byte & 0x80);
85 return value;
86}
87
88static int32_t InputStream_readLeb128_i32(struct InputStream *self) {
89 uint32_t value = 0;
90 uint8_t shift = 0;
91 uint8_t byte;
92 do {
93 byte = InputStream_readByte(self);
94 assert(shift < 64);
95 value |= (uint32_t)(byte & 0x7F) << shift;
96 shift += 7;
97 } while (byte & 0x80);
98 if (shift < 32) {
99 uint32_t mask = -((uint32_t)1 << shift);
100 if (byte & 0x40) value |= mask; else value &= ~mask;
101 }
102 return (int32_t)value;
103}
104
105static int64_t InputStream_readLeb128_u64(struct InputStream *self) {
106 uint64_t value = 0;
107 uint8_t shift = 0;
108 uint8_t byte;
109 do {
110 byte = InputStream_readByte(self);
111 assert(shift < 64);
112 value |= (uint64_t)(byte & 0x7F) << shift;
113 shift += 7;
114 } while (byte & 0x80);
115 return value;
116}
117
118static int64_t InputStream_readLeb128_i64(struct InputStream *self) {
119 uint64_t value = 0;
120 uint8_t shift = 0;
121 uint8_t byte;
122 do {
123 byte = InputStream_readByte(self);
124 assert(shift < 64);
125 value |= (uint64_t)(byte & 0x7F) << shift;
126 shift += 7;
127 } while (byte & 0x80);
128 if (shift < 64) {
129 uint64_t mask = -((uint64_t)1 << shift);
130 if (byte & 0x40) value |= mask; else value &= ~mask;
131 }
132 return (int64_t)value;
133}
134
135static char *InputStream_readName(struct InputStream *self) {
136 uint32_t len = InputStream_readLeb128_u32(self);
137 char *name = malloc(len + 1);
138 if (name == NULL) panic("out of memory");
139 if (fread(name, 1, len, self->stream) != len) panic("unexpected end of input stream");
140 name[len] = 0;
141 return name;
142}
143
144static void InputStream_skipBytes(struct InputStream *self, size_t len) {
145 if (fseek(self->stream, len, SEEK_CUR) == -1) panic("unexpected end of input stream");
146}
147
148static uint32_t InputStream_skipToSection(struct InputStream *self, uint8_t expected_id) {
149 while (true) {
150 uint8_t id = InputStream_readByte(self);
151 uint32_t size = InputStream_readLeb128_u32(self);
152 if (id == expected_id) return size;
153 InputStream_skipBytes(self, size);
154 }
155}
156
157struct ResultType {
158 uint32_t len;
159 int8_t types[1];
160};
161static struct ResultType *InputStream_readResultType(struct InputStream *self) {
162 uint32_t len = InputStream_readLeb128_u32(self);
163 struct ResultType *result_type = malloc(offsetof(struct ResultType, types) + sizeof(int8_t) * len);
164 if (result_type == NULL) panic("out of memory");
165 result_type->len = len;
166 for (uint32_t i = 0; i < len; i += 1) {
167 int64_t val_type = InputStream_readLeb128_i64(self);
168 switch (val_type) {
169 case WasmValType_i32: case WasmValType_i64:
170 case WasmValType_f32: case WasmValType_f64:
171 break;
172
173 default: panic("unsupported valtype");
174 }
175 result_type->types[i] = val_type;
176 }
177 return result_type;
178}
179
180struct Limits {
181 uint32_t min;
182 uint32_t max;
183};
184static struct Limits InputStream_readLimits(struct InputStream *self) {
185 struct Limits limits;
186 uint8_t kind = InputStream_readByte(self);
187 limits.min = InputStream_readLeb128_u32(self);
188 switch (kind) {
189 case 0x00: limits.max = UINT32_MAX; break;
190 case 0x01: limits.max = InputStream_readLeb128_u32(self); break;
191 default: panic("unsupported limit kind");
192 }
193 return limits;
194}
195
196#endif /* INPUT_STREAM_H */