159 lines
6.8 KiB
TypeScript

import { Type, SectionId, ExternalKind } from "./common";
export { Type, SectionId, ExternalKind };
/** Cached compiled parser. */
var compiled: WebAssembly.Module | null = null;
declare var WASM_DATA: string; // injected by webpack
if (typeof WASM_DATA !== "string") WASM_DATA = require("fs").readFileSync(__dirname + "/../build/index.wasm", "base64");
/** Options specified to the parser. The `onSection` callback determines the sections being evaluated in detail. */
export interface ParseOptions {
/** Called with each section in the binary. Returning `true` evaluates the section. */
onSection?(id: SectionId, payloadOff: number, payloadLen: number, nameOff: number, nameLen: number): boolean;
/** Called with each function type if the type section is evaluated. */
onType?(index: number, form: number): void;
/** Called with each function parameter if the type section is evaluated. */
onTypeParam?(index: number, paramIndex: number, paramType: Type): void;
/** Called with each function return type if the type section is evaluated. */
onTypeReturn?(index: number, returnIndex: number, returnType: Type): void;
/** Called with each import if the import section is evaluated. */
onImport?(index: number, kind: ExternalKind, moduleOff: number, moduleLen: number, fieldOff: number, fieldLen: number): void;
/** Called with each function import if the import section is evaluated. */
onFunctionImport?(index: number, type: number): void;
/** Called with each table import if the import section is evaluated. */
onTableImport?(index: number, type: Type, initial: number, maximum: number, flags: number): void;
/** Called with each memory import if the import section is evaluated. */
onMemoryImport?(index: number, initial: number, maximum: number, flags: number): void;
/** Called with each global import if the import section is evaluated. */
onGlobalImport?(index: number, type: Type, mutability: number): void;
/** Called with each memory if the memory section is evaluated.*/
onMemory?(index: number, initial: number, maximum: number, flags: number): void;
/** Called with each function if the function section is evaluated. */
onFunction?(index: number, typeIndex: number): void;
/** Called with each global if the global section is evaluated. */
onGlobal?(index: number, type: Type, mutability: number): void;
/** Called with the start function index if the start section is evaluated. */
onStart?(index: number): void;
/** Called with each export if the export section is evaluated. */
onExport?(index: number, kind: ExternalKind, kindIndex: number, nameOff: number, nameLen: number): void;
/** Called with the source map URL if the 'sourceMappingURL' section is evaluated. */
onSourceMappingURL?(offset: number, length: number): void;
/** Called with the module name if present and the 'name' section is evaluated. */
onModuleName?(offset: number, length: number): void;
/** Called with each function name if present and the 'name' section is evaluated. */
onFunctionName?(index: number, offset: number, length: number): void;
/** Called with each local name if present and the 'name' section is evaluated. */
onLocalName?(funcIndex: number, index: number, offset: number, length: number): void;
}
/** Parses the contents of a WebAssembly binary according to the specified options. */
export function parse(binary: Uint8Array, options?: ParseOptions): void {
if (!options) options = {};
// compile the parser if not yet compiled
if (!compiled) compiled = new WebAssembly.Module(base64_decode(WASM_DATA));
// use the binary as the parser's memory
var nBytes = binary.length;
var nPages = ((nBytes + 0xffff) & ~0xffff) >> 16;
var memory = new WebAssembly.Memory({ initial: nPages });
var buffer = new Uint8Array(memory.buffer);
buffer.set(binary);
// provide a way to read strings from memory
parse.readString = (offset: number, length: number): string => utf8_read(buffer, offset, offset + length);
// instantiate the parser and return its exports
function nop(): void {}
var imports = { env: { memory } };
[ "onSection",
"onType",
"onTypeParam",
"onTypeReturn",
"onImport",
"onFunctionImport",
"onTableImport",
"onMemoryImport",
"onGlobalImport",
"onMemory",
"onFunction",
"onGlobal",
"onExport",
"onStart",
"onSourceMappingURL",
"onModuleName",
"onFunctionName",
"onLocalName"
].forEach((name: string): void => imports.env[name] = options[name] || nop);
var instance = new WebAssembly.Instance(compiled, imports);
instance.exports.parse(0, nBytes);
}
export declare namespace parse {
/** Utility function for reading an UTF8 encoded string from memory while parsing. */
function readString(offset: number, length: number): string;
}
// see: https://github.com/dcodeIO/protobuf.js/tree/master/lib/utf8
function utf8_read(buffer: Uint8Array, start: number, end: number): string {
var len = end - start;
if (len < 1) return "";
var parts: string[] | null = null,
chunk: number[] = [],
i = 0, // char offset
t = 0; // temporary
while (start < end) {
t = buffer[start++];
if (t < 128) {
chunk[i++] = t;
} else if (t > 191 && t < 224) {
chunk[i++] = (t & 31) << 6 | buffer[start++] & 63;
} else if (t > 239 && t < 365) {
t = ((t & 7) << 18 | (buffer[start++] & 63) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63) - 0x10000;
chunk[i++] = 0xD800 + (t >> 10);
chunk[i++] = 0xDC00 + (t & 1023);
} else {
chunk[i++] = (t & 15) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63;
}
if (i > 8191) {
(parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));
i = 0;
}
}
if (parts) {
if (i) parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));
return parts.join("");
}
return String.fromCharCode.apply(String, chunk.slice(0, i));
}
// see: https://github.com/dcodeIO/protobuf.js/tree/master/lib/base64
function base64_decode(string: string): Uint8Array {
var length = string.length;
if (length) {
let n = 0,
p = length;
while (--p % 4 > 1 && string.charCodeAt(p) === 61) ++n;
length = Math.ceil(length * 3) / 4 - n;
}
var buffer = new Uint8Array(length);
var j = 0, o = 0, t = 0;
for (let i = 0, k = string.length; i < k;) {
let c = string.charCodeAt(i++);
if (c === 61 && j > 1) break;
if ((c = s64[c]) === undefined) throw Error();
switch (j) {
case 0: { t = c; j = 1; break; }
case 1: { buffer[o++] = t << 2 | (c & 48) >> 4; t = c; j = 2; break; }
case 2: { buffer[o++] = (t & 15) << 4 | (c & 60) >> 2; t = c; j = 3; break; }
case 3: { buffer[o++] = (t & 3) << 6 | c; j = 0; break; }
}
}
if (j === 1) throw Error();
return buffer;
}
var s64 = new Array(123);
for (let i = 0; i < 64;) s64[i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++;