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 */