const Stream = require('buffer-pipe') const leb = require('leb128') const LANGUAGE_TYPES = { 'actor': 0x0, 'buf': 0x1, 'i32': 0x7f, 'i64': 0x7e, 'f32': 0x7d, 'f64': 0x7c, 'anyFunc': 0x70, 'func': 0x60, 'block_type': 0x40, 0x0: 'actor', 0x1: 'buf', 0x7f: 'i32', 0x7e: 'i64', 0x7d: 'f32', 0x7c: 'f64', 0x70: 'anyFunc', 0x60: 'func', 0x40: 'block_type' } function encodeJSON (json) { const stream = new Stream() encodeCustomSection('type', json, stream, encodeType) encodeCustomSection('typeMap', json, stream, encodeTypeMap) return stream.buffer } function encodeCustomSection (name, json, stream, encodingFunc) { stream.write([0]) let payload = new Stream() // encode type leb.unsigned.write(name.length, payload) payload.write(name) encodingFunc(json[name], payload) // write the size of the payload leb.unsigned.write(payload.bytesWrote, stream) stream.write(payload.buffer) return stream } function encodeTypeMap (json, stream) { leb.unsigned.write(json.length, stream) for (let entry of json) { leb.unsigned.write(entry.func, stream) leb.unsigned.write(entry.type, stream) } return stream } function decodeTypeMap (buf) { const stream = new Stream(Buffer.from(buf)) let numOfEntries = leb.unsigned.read(stream) const json = [] while (numOfEntries--) { json.push({ func: leb.unsigned.readBn(stream).toNumber(), type: leb.unsigned.readBn(stream).toNumber() }) } return json } function encodeType (json, stream = new Stream()) { let binEntries = new Stream() leb.unsigned.write(json.length, binEntries) for (let entry of json) { // a single type entry binary encoded binEntries.write([LANGUAGE_TYPES[entry.form]]) // the form const len = entry.params.length // number of parameters leb.unsigned.write(len, binEntries) if (len !== 0) { binEntries.write(entry.params.map(type => LANGUAGE_TYPES[type])) // the paramter types } binEntries.write([entry.return_type ? 1 : 0]) // number of return types if (entry.return_type) { binEntries.write([LANGUAGE_TYPES[entry.return_type]]) } } stream.write(binEntries.buffer) return stream } function decodeType (buf) { const stream = new Stream(Buffer.from(buf)) const numberOfEntries = leb.unsigned.readBn(stream).toNumber() const json = [] for (let i = 0; i < numberOfEntries; i++) { let type = stream.read(1)[0] const entry = { form: LANGUAGE_TYPES[type], params: [] } let paramCount = leb.unsigned.readBn(stream).toNumber() // parse the entries while (paramCount--) { const type = stream.read(1)[0] entry.params.push(LANGUAGE_TYPES[type]) } const numOfReturns = leb.unsigned.readBn(stream).toNumber() if (numOfReturns) { type = stream.read(1)[0] entry.return_type = LANGUAGE_TYPES[type] } json.push(entry) } return json } function injectCustomSection (custom, wasm) { const preramble = wasm.subarray(0, 8) const body = wasm.subarray(8) return Buffer.concat([preramble, custom, body]) } function inject (wasm, json) { const buf = encodeJSON(json) return injectCustomSection(buf, wasm) } module.exports = { injectCustomSection, inject, decodeType, decodeTypeMap, encodeType, encodeTypeMap, encodeJSON }