Merge branch 'main' of github.com:camillobruni/JetStream into 2024-11-22_driver_prep
diff --git a/JetStreamDriver.js b/JetStreamDriver.js
index 7bcd27d..281e103 100644
--- a/JetStreamDriver.js
+++ b/JetStreamDriver.js
@@ -1,7 +1,7 @@
"use strict";
/*
- * Copyright (C) 2018-2022 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,11 +36,17 @@
globalThis.customTestList ??= [];
let shouldReport = false;
+let startDelay;
if (typeof(URLSearchParams) !== "undefined") {
const urlParameters = new URLSearchParams(window.location.search);
shouldReport = urlParameters.has('report') && urlParameters.get('report').toLowerCase() == 'true';
+ if (shouldReport)
+ startDelay = 4000;
+ if (urlParameters.has('startDelay'))
+ startDelay = urlParameters.get('startDelay');
if (urlParameters.has('test'))
customTestList = urlParameters.getAll("test");
+
}
// Used for the promise representing the current benchmark run.
@@ -158,7 +164,7 @@
const minutes = time.getMinutes();
const seconds = time.getSeconds();
const milliSeconds = time.getMilliseconds();
- const result = "" + minutes + ":";
+ let result = "" + minutes + ":";
result = result + (seconds < 10 ? "0" : "") + seconds + ".";
result = result + (milliSeconds < 10 ? "00" : (milliSeconds < 100 ? "0" : "")) + milliSeconds;
@@ -331,7 +337,13 @@
} else
globalObject = runString("");
- globalObject.console = { log: globalObject.print, warn: (e) => { print("Warn: " + e); /*$vm.abort();*/ } }
+ globalObject.console = {
+ log: globalObject.print,
+ warn: (e) => { print("Warn: " + e); },
+ error: (e) => { print("Error: " + e); },
+ debug: (e) => { print("Debug: " + e); },
+ };
+
globalObject.self = globalObject;
globalObject.top = {
currentResolve,
@@ -415,8 +427,8 @@
await this.prefetchResourcesForBrowser();
await this.fetchResources();
this.prepareToRun();
- if (isInBrowser && shouldReport) {
- setTimeout(() => this.start(), 4000);
+ if (isInBrowser && startDelay !== undefined) {
+ setTimeout(() => this.start(), startDelay);
}
}
@@ -545,10 +557,11 @@
if (__benchmark.prepareForNextIteration)
__benchmark.prepareForNextIteration();
- ${this.preiterationCode}
+ ${this.preIterationCode}
let start = performance.now();
__benchmark.runIteration();
let end = performance.now();
+ ${this.postIterationCode}
results.push(Math.max(1, end - start));
}
@@ -567,11 +580,24 @@
get prerunCode() { return null; }
- get preiterationCode() {
+ get preIterationCode() {
+ let code = "";
if (this.plan.deterministicRandom)
- return `Math.random.__resetSeed();`;
+ code += `Math.random.__resetSeed();`;
- return "";
+ if (globalThis.customPreIterationCode)
+ code += customPreIterationCode;
+
+ return code;
+ }
+
+ get postIterationCode() {
+ let code = "";
+
+ if (globalThis.customPostIterationCode)
+ code += customPostIterationCode;
+
+ return code;
}
async run() {
@@ -691,7 +717,7 @@
async doLoadBlob(resource) {
let response;
- const tries = 3;
+ let tries = 3;
while (tries--) {
let hasError = false;
try {
@@ -974,10 +1000,11 @@
let __benchmark = new Benchmark();
let results = [];
for (let i = 0; i < ${this.iterations}; i++) {
- ${this.preiterationCode}
+ ${this.preIterationCode}
let start = performance.now();
await __benchmark.runIteration();
let end = performance.now();
+ ${this.postIterationCode}
results.push(Math.max(1, end - start));
}
if (__benchmark.validate)
@@ -988,6 +1015,95 @@
}
};
+// Meant for wasm benchmarks that are directly compiled with an emcc build script. It might not work for benchmarks built as
+// part of a larger project's build system or a wasm benchmark compiled from a language that doesn't compile with emcc.
+class WasmEMCCBenchmark extends AsyncBenchmark {
+ get prerunCode() {
+ let str = `
+ let verbose = false;
+
+ let globalObject = this;
+
+ abort = quit = function() {
+ if (verbose)
+ console.log('Intercepted quit/abort');
+ };
+
+ oldPrint = globalObject.print;
+ globalObject.print = globalObject.printErr = (...args) => {
+ if (verbose)
+ console.log('Intercepted print: ', ...args);
+ };
+
+ let Module = {
+ preRun: [],
+ postRun: [],
+ noInitialRun: true,
+ print: print,
+ printErr: printErr,
+ setStatus: function(text) {
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
+ },
+ };
+ globalObject.Module = Module;
+ `;
+ return str;
+ }
+
+ get runnerCode() {
+ let str = `function loadBlob(key, path, andThen) {`;
+
+ if (isInBrowser) {
+ str += `
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', path, true);
+ xhr.responseType = 'arraybuffer';
+ xhr.onload = function() {
+ Module[key] = new Int8Array(xhr.response);
+ andThen();
+ };
+ xhr.send(null);
+ `;
+ } else {
+ str += `
+ Module[key] = new Int8Array(read(path, "binary"));
+
+ Module.setStatus = null;
+ Module.monitorRunDependencies = null;
+
+ Promise.resolve(42).then(() => {
+ try {
+ andThen();
+ } catch(e) {
+ console.log("error running wasm:", e);
+ console.log(e.stack);
+ throw e;
+ }
+ })
+ `;
+ }
+
+ str += "}";
+
+ let keys = Object.keys(this.plan.preload);
+ for (let i = 0; i < keys.length; ++i) {
+ str += `loadBlob("${keys[i]}", "${this.plan.preload[keys[i]]}", async () => {\n`;
+ }
+
+ str += super.runnerCode;
+ for (let i = 0; i < keys.length; ++i) {
+ str += `})`;
+ }
+ str += `;`;
+
+ return str;
+ }
+};
+
class WSLBenchmark extends Benchmark {
constructor(...args) {
super(...args);
@@ -1064,7 +1180,7 @@
}
};
-class WasmBenchmark extends Benchmark {
+class WasmLegacyBenchmark extends Benchmark {
constructor(...args) {
super(...args);
@@ -1111,16 +1227,17 @@
};
oldPrint = globalObject.print;
+ oldConsoleLog = globalObject.console.log;
globalObject.print = globalObject.printErr = (...args) => {
if (verbose)
- console.log('Intercepted print: ', ...args);
+ oldConsoleLog('Intercepted print: ', ...args);
};
let Module = {
preRun: [],
postRun: [],
- print: function() { },
- printErr: function() { },
+ print: globalObject.print,
+ printErr: globalObject.print,
setStatus: function(text) {
},
totalDependencies: 0,
@@ -1236,11 +1353,12 @@
console.log(" Startup:", uiFriendlyNumber(this.startupTime));
console.log(" Run time:", uiFriendlyNumber(this.runTime));
+ console.log(" Score:", uiFriendlyNumber(this.score));
if (RAMification) {
console.log(" Current Footprint:", uiFriendlyNumber(this.currentFootprint));
console.log(" Peak Footprint:", uiFriendlyNumber(this.peakFootprint));
}
- console.log(" Score:", uiFriendlyNumber(this.score));
+ console.log(" Wall time:", uiFriendlyDuration(new Date(this.endTime - this.startTime)));
}
};
@@ -1544,15 +1662,6 @@
}),
// Simple
new DefaultBenchmark({
- name: "float-mm.c",
- files: [
- "./simple/float-mm.c.js"
- ],
- iterations: 15,
- worstCaseCount: 2,
- testGroup: SimpleGroup
- }),
- new DefaultBenchmark({
name: "hash-map",
files: [
"./simple/hash-map.js"
@@ -1762,7 +1871,7 @@
testGroup: GeneratorsGroup,
}),
// Wasm
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
name: "HashSet-wasm",
files: [
"./wasm/HashSet.js"
@@ -1772,17 +1881,20 @@
},
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmEMCCBenchmark({
name: "tsf-wasm",
files: [
- "./wasm/tsf.js"
+ "./wasm/TSF/build/tsf.js",
+ "./wasm/TSF/benchmark.js",
],
preload: {
- wasmBinary: "./wasm/tsf.wasm"
+ wasmBinary: "./wasm/TSF/build/tsf.wasm"
},
+ iterations: 15,
+ worstCaseCount: 2,
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
name: "quicksort-wasm",
files: [
"./wasm/quicksort.js"
@@ -1792,17 +1904,19 @@
},
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmEMCCBenchmark({
name: "gcc-loops-wasm",
files: [
- "./wasm/gcc-loops.js"
+ "./wasm/gcc-loops/build/gcc-loops.js",
+ "./wasm/gcc-loops/benchmark.js",
],
preload: {
- wasmBinary: "./wasm/gcc-loops.wasm"
+ wasmBinary: "./wasm/gcc-loops/build/gcc-loops.wasm"
},
+ iterations: 50,
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
name: "richards-wasm",
files: [
"./wasm/richards.js"
@@ -1812,47 +1926,62 @@
},
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
+ name: "sqlite3-wasm",
+ files: [
+ "./sqlite3/polyfills.js",
+ "./sqlite3/build/jswasm/speedtest1.js",
+ "./sqlite3/benchmark.js",
+ ],
+ preload: {
+ wasmBinary: "./sqlite3/build/jswasm/speedtest1.wasm"
+ },
+ benchmarkClass: WasmLegacyBenchmark,
+ testGroup: WasmGroup
+ }),
+ new WasmEMCCBenchmark({
name: "tfjs-wasm",
files: [
- "./wasm/tfjs-model-helpers.js",
- "./wasm/tfjs-model-mobilenet-v3.js",
- "./wasm/tfjs-model-mobilenet-v1.js",
- "./wasm/tfjs-model-coco-ssd.js",
- "./wasm/tfjs-model-use.js",
- "./wasm/tfjs-model-use-vocab.js",
- "./wasm/tfjs-bundle.js",
- "./wasm/tfjs.js",
- "./wasm/tfjs-benchmark.js"
+ "./wasm/tfjs/tfjs-model-helpers.js",
+ "./wasm/tfjs/tfjs-model-mobilenet-v3.js",
+ "./wasm/tfjs/tfjs-model-mobilenet-v1.js",
+ "./wasm/tfjs/tfjs-model-coco-ssd.js",
+ "./wasm/tfjs/tfjs-model-use.js",
+ "./wasm/tfjs/tfjs-model-use-vocab.js",
+ "./wasm/tfjs/tfjs-bundle.js",
+ "./wasm/tfjs/tfjs.js",
+ "./wasm/tfjs/benchmark.js"
],
preload: {
- tfjsBackendWasmBlob: "./wasm/tfjs-backend-wasm.wasm",
+ tfjsBackendWasmBlob: "./wasm/tfjs/tfjs-backend-wasm.wasm",
},
- async: true,
+ iterations: 15,
+ worstCaseCount: 2,
deterministicRandom: true,
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmEMCCBenchmark({
name: "tfjs-wasm-simd",
files: [
- "./wasm/tfjs-model-helpers.js",
- "./wasm/tfjs-model-mobilenet-v3.js",
- "./wasm/tfjs-model-mobilenet-v1.js",
- "./wasm/tfjs-model-coco-ssd.js",
- "./wasm/tfjs-model-use.js",
- "./wasm/tfjs-model-use-vocab.js",
- "./wasm/tfjs-bundle.js",
- "./wasm/tfjs.js",
- "./wasm/tfjs-benchmark.js"
+ "./wasm/tfjs/tfjs-model-helpers.js",
+ "./wasm/tfjs/tfjs-model-mobilenet-v3.js",
+ "./wasm/tfjs/tfjs-model-mobilenet-v1.js",
+ "./wasm/tfjs/tfjs-model-coco-ssd.js",
+ "./wasm/tfjs/tfjs-model-use.js",
+ "./wasm/tfjs/tfjs-model-use-vocab.js",
+ "./wasm/tfjs/tfjs-bundle.js",
+ "./wasm/tfjs/tfjs.js",
+ "./wasm/tfjs/benchmark.js"
],
preload: {
- tfjsBackendWasmSimdBlob: "./wasm/tfjs-backend-wasm-simd.wasm",
+ tfjsBackendWasmSimdBlob: "./wasm/tfjs/tfjs-backend-wasm-simd.wasm",
},
- async: true,
+ iterations: 40,
+ worstCaseCount: 3,
deterministicRandom: true,
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
name: "argon2-wasm",
files: [
"./wasm/argon2-bundle.js",
@@ -1864,7 +1993,7 @@
},
testGroup: WasmGroup
}),
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
name: "argon2-wasm-simd",
files: [
"./wasm/argon2-bundle.js",
@@ -1932,7 +2061,7 @@
testGroup: WSLGroup
}),
// 8bitbench
- new WasmBenchmark({
+ new WasmLegacyBenchmark({
name: "8bitbench-wasm",
files: [
"./8bitbench/lib/fast-text-encoding-1.0.3/text.js",
diff --git a/SunSpider/crypto-md5.js b/SunSpider/crypto-md5.js
index ca33650..2af8459 100644
--- a/SunSpider/crypto-md5.js
+++ b/SunSpider/crypto-md5.js
@@ -181,9 +181,7 @@
*/
function safe_add(x, y)
{
- var lsw = (x & 0xFFFF) + (y & 0xFFFF);
- var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
- return (msw << 16) | (lsw & 0xFFFF);
+ return ((x & 0xffffffff) + (y & 0xffffffff)) & 0xffffffff
}
/*
diff --git a/SunSpider/crypto-sha1.js b/SunSpider/crypto-sha1.js
index fb5c4cb..1ed248b 100644
--- a/SunSpider/crypto-sha1.js
+++ b/SunSpider/crypto-sha1.js
@@ -127,9 +127,7 @@
*/
function safe_add(x, y)
{
- var lsw = (x & 0xFFFF) + (y & 0xFFFF);
- var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
- return (msw << 16) | (lsw & 0xFFFF);
+ return ((x & 0xffffffff) + (y & 0xffffffff)) & 0xffffffff
}
/*
diff --git a/cli.js b/cli.js
index d9fffcb..956b4d8 100644
--- a/cli.js
+++ b/cli.js
@@ -32,9 +32,13 @@
if (isD8)
globalThis.readFile = read;
const isSpiderMonkey = typeof newGlobal !== "undefined";
-if (isSpiderMonkey)
+if (isSpiderMonkey) {
globalThis.readFile = readRelativeToScript;
+ globalThis.arguments = scriptArgs;
+}
+if (typeof arguments !== "undefined" && arguments.length > 0)
+ testList = arguments.slice();
if (typeof testList === "undefined")
testList = undefined;
diff --git a/simple/float-mm.c b/simple/float-mm.c
deleted file mode 100644
index 3722c9b..0000000
--- a/simple/float-mm.c
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#define nil 0
-#define false 0
-#define true 1
-#define bubblebase 1.61f
-#define dnfbase 3.5f
-#define permbase 1.75f
-#define queensbase 1.83f
-#define towersbase 2.39f
-#define quickbase 1.92f
-#define intmmbase 1.46f
-#define treebase 2.5f
-#define mmbase 0.0f
-#define fpmmbase 2.92f
-#define puzzlebase 0.5f
-#define fftbase 0.0f
-#define fpfftbase 4.44f
- /* Towers */
-#define maxcells 18
-
- /* Intmm, Mm */
-#define rowsize 40
-
- /* Puzzle */
-#define size 511
-#define classmax 3
-#define typemax 12
-#define d 8
-
- /* Bubble, Quick */
-#define sortelements 5000
-#define srtelements 500
-
- /* fft */
-#define fftsize 256
-#define fftsize2 129
-/*
-type */
- /* Perm */
-#define permrange 10
-
- /* tree */
-struct node {
- struct node *left,*right;
- int val;
-};
-
- /* Towers */ /*
- discsizrange = 1..maxcells; */
-#define stackrange 3
-/* cellcursor = 0..maxcells; */
-struct element {
- int discsize;
- int next;
-};
-/* emsgtype = packed array[1..15] of char;
-*/
- /* Intmm, Mm */ /*
- index = 1 .. rowsize;
- intmatrix = array [index,index] of integer;
- realmatrix = array [index,index] of real;
-*/
- /* Puzzle */ /*
- piececlass = 0..classmax;
- piecetype = 0..typemax;
- position = 0..size;
-*/
- /* Bubble, Quick */ /*
- listsize = 0..sortelements;
- sortarray = array [listsize] of integer;
-*/
- /* FFT */
-struct complex { float rp, ip; } ;
-/*
- carray = array [1..fftsize] of complex ;
- c2array = array [1..fftsize2] of complex ;
-*/
-
-float value, fixed, floated;
-
- /* global */
-long seed; /* converted to long for 16 bit WR*/
-
- /* Perm */
-int permarray[permrange+1];
-/* converted pctr to unsigned int for 16 bit WR*/
-unsigned int pctr;
-
- /* tree */
-struct node *tree;
-
- /* Towers */
-int stack[stackrange+1];
-struct element cellspace[maxcells+1];
-int freelist, movesdone;
-
- /* Intmm, Mm */
-
-int ima[rowsize+1][rowsize+1], imb[rowsize+1][rowsize+1], imr[rowsize+1][rowsize+1];
-float rma[rowsize+1][rowsize+1], rmb[rowsize+1][rowsize+1], rmr[rowsize+1][rowsize+1];
-
- /* Puzzle */
-int piececount[classmax+1], class[typemax+1], piecemax[typemax+1];
-int puzzl[size+1], p[typemax+1][size+1], n, kount;
-
- /* Bubble, Quick */
-int sortlist[sortelements+1], biggest, littlest, top;
-
- /* FFT */
-struct complex z[fftsize+1], w[fftsize+1], e[fftsize2+1];
-float zr, zi;
-
-void Initrand () {
- seed = 74755L; /* constant to long WR*/
-}
-
-int Rand () {
- seed = (seed * 1309L + 13849L) & 65535L; /* constants to long WR*/
- return( (int)seed ); /* typecast back to int WR*/
-}
-
-
- /* Multiplies two real matrices. */
-
-void rInitmatrix ( float m[rowsize+1][rowsize+1] ) {
- int temp, i, j;
- for ( i = 1; i <= rowsize; i++ )
- for ( j = 1; j <= rowsize; j++ ) {
- temp = Rand();
- m[i][j] = (float)(temp - (temp/120)*120 - 60)/3;
- }
-}
-
-void rInnerproduct(float *result, float a[rowsize+1][rowsize+1], float b[rowsize+1][rowsize+1], int row, int column) {
- /* computes the inner product of A[row,*] and B[*,column] */
- int i;
- *result = 0.0f;
- for (i = 1; i<=rowsize; i++) *result = *result+a[row][i]*b[i][column];
-}
-
-void Mm (int run) {
- int i, j;
- Initrand();
- rInitmatrix (rma);
- rInitmatrix (rmb);
- for ( i = 1; i <= rowsize; i++ )
- for ( j = 1; j <= rowsize; j++ )
- rInnerproduct(&rmr[i][j],rma,rmb,i,j);
- if (run < rowsize)
- printf("%f\n", rmr[run + 1][run + 1]);
-}
-
-int main()
-{
- int i;
- for (i = 0; i < 5000; i++) Mm(i);
- return 0;
-}
diff --git a/simple/float-mm.c.js b/simple/float-mm.c.js
deleted file mode 100644
index 68efab6..0000000
--- a/simple/float-mm.c.js
+++ /dev/null
@@ -1,4662 +0,0 @@
-// The Module object: Our interface to the outside world. We import
-// and export values on it, and do the work to get that through
-// closure compiler if necessary. There are various ways Module can be used:
-// 1. Not defined. We create it here
-// 2. A function parameter, function(Module) { ..generated code.. }
-// 3. pre-run appended it, var Module = {}; ..generated code..
-// 4. External script tag defines var Module.
-// We need to do an eval in order to handle the closure compiler
-// case, where this code here is minified but Module was defined
-// elsewhere (e.g. case 4 above). We also need to check if Module
-// already exists (e.g. case 3 above).
-// Note that if you want to run closure, and also to use Module
-// after the generated code, you will need to define var Module = {};
-// before the code. Then that object will be used in the code, and you
-// can continue to use Module afterwards as well.
-function run() {
-
-var Module;
-if (!Module) Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
-
-// Sometimes an existing Module object exists with properties
-// meant to overwrite the default module functionality. Here
-// we collect those properties and reapply _after_ we configure
-// the current environment's defaults to avoid having to be so
-// defensive during initialization.
-var moduleOverrides = {};
-for (var key in Module) {
- if (Module.hasOwnProperty(key)) {
- moduleOverrides[key] = Module[key];
- }
-}
-
-// The environment setup code below is customized to use Module.
-// *** Environment setup code ***
-var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
-var ENVIRONMENT_IS_WEB = typeof window === 'object';
-var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
-var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
-
-if (ENVIRONMENT_IS_NODE) {
- // Expose functionality in the same simple way that the shells work
- // Note that we pollute the global namespace here, otherwise we break in node
- if (!Module['print']) Module['print'] = function print(x) {
- process['stdout'].write(x + '\n');
- };
- if (!Module['printErr']) Module['printErr'] = function printErr(x) {
- process['stderr'].write(x + '\n');
- };
-
- var nodeFS = require('fs');
- var nodePath = require('path');
-
- Module['read'] = function read(filename, binary) {
- filename = nodePath['normalize'](filename);
- var ret = nodeFS['readFileSync'](filename);
- // The path is absolute if the normalized version is the same as the resolved.
- if (!ret && filename != nodePath['resolve'](filename)) {
- filename = path.join(__dirname, '..', 'src', filename);
- ret = nodeFS['readFileSync'](filename);
- }
- if (ret && !binary) ret = ret.toString();
- return ret;
- };
-
- Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
-
- Module['load'] = function load(f) {
- globalEval(read(f));
- };
-
- Module['arguments'] = process['argv'].slice(2);
-
- module['exports'] = Module;
-}
-else if (ENVIRONMENT_IS_SHELL) {
- if (!Module['print']) Module['print'] = print;
- if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
-
- if (typeof read != 'undefined') {
- Module['read'] = read;
- } else {
- Module['read'] = function read() { throw 'no read() available (jsc?)' };
- }
-
- Module['readBinary'] = function readBinary(f) {
- return read(f, 'binary');
- };
-
- if (typeof scriptArgs != 'undefined') {
- Module['arguments'] = scriptArgs;
- } else if (typeof arguments != 'undefined') {
- Module['arguments'] = arguments;
- }
-
- this['Module'] = Module;
-
- eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
-}
-else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
- Module['read'] = function read(url) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, false);
- xhr.send(null);
- return xhr.responseText;
- };
-
- if (typeof arguments != 'undefined') {
- Module['arguments'] = arguments;
- }
-
- if (typeof console !== 'undefined') {
- if (!Module['print']) Module['print'] = function print(x) {
- console.log(x);
- };
- if (!Module['printErr']) Module['printErr'] = function printErr(x) {
- console.log(x);
- };
- } else {
- // Probably a worker, and without console.log. We can do very little here...
- var TRY_USE_DUMP = false;
- if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
- dump(x);
- }) : (function(x) {
- // self.postMessage(x); // enable this if you want stdout to be sent as messages
- }));
- }
-
- if (ENVIRONMENT_IS_WEB) {
- this['Module'] = Module;
- } else {
- Module['load'] = importScripts;
- }
-}
-else {
- // Unreachable because SHELL is dependant on the others
- throw 'Unknown runtime environment. Where are we?';
-}
-
-function globalEval(x) {
- eval.call(null, x);
-}
-if (!Module['load'] == 'undefined' && Module['read']) {
- Module['load'] = function load(f) {
- globalEval(Module['read'](f));
- };
-}
-if (!Module['print']) {
- Module['print'] = function(){};
-}
-if (!Module['printErr']) {
- Module['printErr'] = Module['print'];
-}
-if (!Module['arguments']) {
- Module['arguments'] = [];
-}
-// *** Environment setup code ***
-
-// Closure helpers
-Module.print = Module['print'];
-Module.printErr = Module['printErr'];
-
-// Callbacks
-Module['preRun'] = [];
-Module['postRun'] = [];
-
-// Merge back in the overrides
-for (var key in moduleOverrides) {
- if (moduleOverrides.hasOwnProperty(key)) {
- Module[key] = moduleOverrides[key];
- }
-}
-
-
-
-// === Auto-generated preamble library stuff ===
-
-//========================================
-// Runtime code shared with compiler
-//========================================
-
-var Runtime = {
- stackSave: function () {
- return STACKTOP;
- },
- stackRestore: function (stackTop) {
- STACKTOP = stackTop;
- },
- forceAlign: function (target, quantum) {
- quantum = quantum || 4;
- if (quantum == 1) return target;
- if (isNumber(target) && isNumber(quantum)) {
- return Math.ceil(target/quantum)*quantum;
- } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
- return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
- }
- return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
- },
- isNumberType: function (type) {
- return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
- },
- isPointerType: function isPointerType(type) {
- return type[type.length-1] == '*';
-},
- isStructType: function isStructType(type) {
- if (isPointerType(type)) return false;
- if (isArrayType(type)) return true;
- if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
- // See comment in isStructPointerType()
- return type[0] == '%';
-},
- INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
- FLOAT_TYPES: {"float":0,"double":0},
- or64: function (x, y) {
- var l = (x | 0) | (y | 0);
- var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
- return l + h;
- },
- and64: function (x, y) {
- var l = (x | 0) & (y | 0);
- var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
- return l + h;
- },
- xor64: function (x, y) {
- var l = (x | 0) ^ (y | 0);
- var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
- return l + h;
- },
- getNativeTypeSize: function (type) {
- switch (type) {
- case 'i1': case 'i8': return 1;
- case 'i16': return 2;
- case 'i32': return 4;
- case 'i64': return 8;
- case 'float': return 4;
- case 'double': return 8;
- default: {
- if (type[type.length-1] === '*') {
- return Runtime.QUANTUM_SIZE; // A pointer
- } else if (type[0] === 'i') {
- var bits = parseInt(type.substr(1));
- assert(bits % 8 === 0);
- return bits/8;
- } else {
- return 0;
- }
- }
- }
- },
- getNativeFieldSize: function (type) {
- return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
- },
- dedup: function dedup(items, ident) {
- var seen = {};
- if (ident) {
- return items.filter(function(item) {
- if (seen[item[ident]]) return false;
- seen[item[ident]] = true;
- return true;
- });
- } else {
- return items.filter(function(item) {
- if (seen[item]) return false;
- seen[item] = true;
- return true;
- });
- }
-},
- set: function set() {
- var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
- var ret = {};
- for (var i = 0; i < args.length; i++) {
- ret[args[i]] = 0;
- }
- return ret;
-},
- STACK_ALIGN: 8,
- getAlignSize: function (type, size, vararg) {
- // we align i64s and doubles on 64-bit boundaries, unlike x86
- if (!vararg && (type == 'i64' || type == 'double')) return 8;
- if (!type) return Math.min(size, 8); // align structures internally to 64 bits
- return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
- },
- calculateStructAlignment: function calculateStructAlignment(type) {
- type.flatSize = 0;
- type.alignSize = 0;
- var diffs = [];
- var prev = -1;
- var index = 0;
- type.flatIndexes = type.fields.map(function(field) {
- index++;
- var size, alignSize;
- if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
- size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
- alignSize = Runtime.getAlignSize(field, size);
- } else if (Runtime.isStructType(field)) {
- if (field[1] === '0') {
- // this is [0 x something]. When inside another structure like here, it must be at the end,
- // and it adds no size
- // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
- size = 0;
- if (Types.types[field]) {
- alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
- } else {
- alignSize = type.alignSize || QUANTUM_SIZE;
- }
- } else {
- size = Types.types[field].flatSize;
- alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
- }
- } else if (field[0] == 'b') {
- // bN, large number field, like a [N x i8]
- size = field.substr(1)|0;
- alignSize = 1;
- } else if (field[0] === '<') {
- // vector type
- size = alignSize = Types.types[field].flatSize; // fully aligned
- } else if (field[0] === 'i') {
- // illegal integer field, that could not be legalized because it is an internal structure field
- // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
- size = alignSize = parseInt(field.substr(1))/8;
- assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
- } else {
- assert(false, 'invalid type for calculateStructAlignment');
- }
- if (type.packed) alignSize = 1;
- type.alignSize = Math.max(type.alignSize, alignSize);
- var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
- type.flatSize = curr + size;
- if (prev >= 0) {
- diffs.push(curr-prev);
- }
- prev = curr;
- return curr;
- });
- if (type.name_ && type.name_[0] === '[') {
- // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
- // allocating a potentially huge array for [999999 x i8] etc.
- type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
- }
- type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
- if (diffs.length == 0) {
- type.flatFactor = type.flatSize;
- } else if (Runtime.dedup(diffs).length == 1) {
- type.flatFactor = diffs[0];
- }
- type.needsFlattening = (type.flatFactor != 1);
- return type.flatIndexes;
- },
- generateStructInfo: function (struct, typeName, offset) {
- var type, alignment;
- if (typeName) {
- offset = offset || 0;
- type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
- if (!type) return null;
- if (type.fields.length != struct.length) {
- printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
- return null;
- }
- alignment = type.flatIndexes;
- } else {
- var type = { fields: struct.map(function(item) { return item[0] }) };
- alignment = Runtime.calculateStructAlignment(type);
- }
- var ret = {
- __size__: type.flatSize
- };
- if (typeName) {
- struct.forEach(function(item, i) {
- if (typeof item === 'string') {
- ret[item] = alignment[i] + offset;
- } else {
- // embedded struct
- var key;
- for (var k in item) key = k;
- ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
- }
- });
- } else {
- struct.forEach(function(item, i) {
- ret[item[1]] = alignment[i];
- });
- }
- return ret;
- },
- dynCall: function (sig, ptr, args) {
- if (args && args.length) {
- if (!args.splice) args = Array.prototype.slice.call(args);
- args.splice(0, 0, ptr);
- return Module['dynCall_' + sig].apply(null, args);
- } else {
- return Module['dynCall_' + sig].call(null, ptr);
- }
- },
- functionPointers: [],
- addFunction: function (func) {
- for (var i = 0; i < Runtime.functionPointers.length; i++) {
- if (!Runtime.functionPointers[i]) {
- Runtime.functionPointers[i] = func;
- return 2*(1 + i);
- }
- }
- throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
- },
- removeFunction: function (index) {
- Runtime.functionPointers[(index-2)/2] = null;
- },
- getAsmConst: function (code, numArgs) {
- // code is a constant string on the heap, so we can cache these
- if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
- var func = Runtime.asmConstCache[code];
- if (func) return func;
- var args = [];
- for (var i = 0; i < numArgs; i++) {
- args.push(String.fromCharCode(36) + i); // $0, $1 etc
- }
- code = Pointer_stringify(code);
- if (code[0] === '"') {
- // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
- if (code.indexOf('"', 1) === code.length-1) {
- code = code.substr(1, code.length-2);
- } else {
- // something invalid happened, e.g. EM_ASM("..code($0)..", input)
- abort('invalid EM_ASM input |' + code + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
- }
- }
- return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + code + ' })'); // new Function does not allow upvars in node
- },
- warnOnce: function (text) {
- if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
- if (!Runtime.warnOnce.shown[text]) {
- Runtime.warnOnce.shown[text] = 1;
- Module.printErr(text);
- }
- },
- funcWrappers: {},
- getFuncWrapper: function (func, sig) {
- assert(sig);
- if (!Runtime.funcWrappers[func]) {
- Runtime.funcWrappers[func] = function dynCall_wrapper() {
- return Runtime.dynCall(sig, func, arguments);
- };
- }
- return Runtime.funcWrappers[func];
- },
- UTF8Processor: function () {
- var buffer = [];
- var needed = 0;
- this.processCChar = function (code) {
- code = code & 0xFF;
-
- if (buffer.length == 0) {
- if ((code & 0x80) == 0x00) { // 0xxxxxxx
- return String.fromCharCode(code);
- }
- buffer.push(code);
- if ((code & 0xE0) == 0xC0) { // 110xxxxx
- needed = 1;
- } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
- needed = 2;
- } else { // 11110xxx
- needed = 3;
- }
- return '';
- }
-
- if (needed) {
- buffer.push(code);
- needed--;
- if (needed > 0) return '';
- }
-
- var c1 = buffer[0];
- var c2 = buffer[1];
- var c3 = buffer[2];
- var c4 = buffer[3];
- var ret;
- if (buffer.length == 2) {
- ret = String.fromCharCode(((c1 & 0x1F) << 6) | (c2 & 0x3F));
- } else if (buffer.length == 3) {
- ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
- } else {
- // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
- var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
- ((c3 & 0x3F) << 6) | (c4 & 0x3F);
- ret = String.fromCharCode(
- Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
- (codePoint - 0x10000) % 0x400 + 0xDC00);
- }
- buffer.length = 0;
- return ret;
- }
- this.processJSString = function processJSString(string) {
- string = unescape(encodeURIComponent(string));
- var ret = [];
- for (var i = 0; i < string.length; i++) {
- ret.push(string.charCodeAt(i));
- }
- return ret;
- }
- },
- getCompilerSetting: function (name) {
- throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
- },
- stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
- staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
- dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
- alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
- makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
- GLOBAL_BASE: 8,
- QUANTUM_SIZE: 4,
- __dummy__: 0
-}
-
-
-Module['Runtime'] = Runtime;
-
-
-
-
-
-
-
-
-
-//========================================
-// Runtime essentials
-//========================================
-
-var __THREW__ = 0; // Used in checking for thrown exceptions.
-
-var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
-var EXITSTATUS = 0;
-
-var undef = 0;
-// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
-// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
-var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
-var tempI64, tempI64b;
-var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
-
-function assert(condition, text) {
- if (!condition) {
- abort('Assertion failed: ' + text);
- }
-}
-
-var globalScope = this;
-
-// C calling interface. A convenient way to call C functions (in C files, or
-// defined with extern "C").
-//
-// Note: LLVM optimizations can inline and remove functions, after which you will not be
-// able to call them. Closure can also do so. To avoid that, add your function to
-// the exports using something like
-//
-// -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
-//
-// @param ident The name of the C function (note that C++ functions will be name-mangled - use extern "C")
-// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
-// 'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
-// @param argTypes An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
-// except that 'array' is not possible (there is no way for us to know the length of the array)
-// @param args An array of the arguments to the function, as native JS values (as in returnType)
-// Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
-// @return The return value, as a native JS value (as in returnType)
-function ccall(ident, returnType, argTypes, args) {
- return ccallFunc(getCFunc(ident), returnType, argTypes, args);
-}
-Module["ccall"] = ccall;
-
-// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
-function getCFunc(ident) {
- try {
- var func = Module['_' + ident]; // closure exported function
- if (!func) func = eval('_' + ident); // explicit lookup
- } catch(e) {
- }
- assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
- return func;
-}
-
-// Internal function that does a C call using a function, not an identifier
-function ccallFunc(func, returnType, argTypes, args) {
- var stack = 0;
- function toC(value, type) {
- if (type == 'string') {
- if (value === null || value === undefined || value === 0) return 0; // null string
- value = intArrayFromString(value);
- type = 'array';
- }
- if (type == 'array') {
- if (!stack) stack = Runtime.stackSave();
- var ret = Runtime.stackAlloc(value.length);
- writeArrayToMemory(value, ret);
- return ret;
- }
- return value;
- }
- function fromC(value, type) {
- if (type == 'string') {
- return Pointer_stringify(value);
- }
- assert(type != 'array');
- return value;
- }
- var i = 0;
- var cArgs = args ? args.map(function(arg) {
- return toC(arg, argTypes[i++]);
- }) : [];
- var ret = fromC(func.apply(null, cArgs), returnType);
- if (stack) Runtime.stackRestore(stack);
- return ret;
-}
-
-// Returns a native JS wrapper for a C function. This is similar to ccall, but
-// returns a function you can call repeatedly in a normal way. For example:
-//
-// var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
-// alert(my_function(5, 22));
-// alert(my_function(99, 12));
-//
-function cwrap(ident, returnType, argTypes) {
- var func = getCFunc(ident);
- return function() {
- return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
- }
-}
-Module["cwrap"] = cwrap;
-
-// Sets a value in memory in a dynamic way at run-time. Uses the
-// type data. This is the same as makeSetValue, except that
-// makeSetValue is done at compile-time and generates the needed
-// code then, whereas this function picks the right code at
-// run-time.
-// Note that setValue and getValue only do *aligned* writes and reads!
-// Note that ccall uses JS types as for defining types, while setValue and
-// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
-function setValue(ptr, value, type, noSafe) {
- type = type || 'i8';
- if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
- switch(type) {
- case 'i1': HEAP8[(ptr)]=value; break;
- case 'i8': HEAP8[(ptr)]=value; break;
- case 'i16': HEAP16[((ptr)>>1)]=value; break;
- case 'i32': HEAP32[((ptr)>>2)]=value; break;
- case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
- case 'float': HEAPF32[((ptr)>>2)]=value; break;
- case 'double': HEAPF64[((ptr)>>3)]=value; break;
- default: abort('invalid type for setValue: ' + type);
- }
-}
-Module['setValue'] = setValue;
-
-// Parallel to setValue.
-function getValue(ptr, type, noSafe) {
- type = type || 'i8';
- if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
- switch(type) {
- case 'i1': return HEAP8[(ptr)];
- case 'i8': return HEAP8[(ptr)];
- case 'i16': return HEAP16[((ptr)>>1)];
- case 'i32': return HEAP32[((ptr)>>2)];
- case 'i64': return HEAP32[((ptr)>>2)];
- case 'float': return HEAPF32[((ptr)>>2)];
- case 'double': return HEAPF64[((ptr)>>3)];
- default: abort('invalid type for setValue: ' + type);
- }
- return null;
-}
-Module['getValue'] = getValue;
-
-var ALLOC_NORMAL = 0; // Tries to use _malloc()
-var ALLOC_STACK = 1; // Lives for the duration of the current function call
-var ALLOC_STATIC = 2; // Cannot be freed
-var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
-var ALLOC_NONE = 4; // Do not allocate
-Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
-Module['ALLOC_STACK'] = ALLOC_STACK;
-Module['ALLOC_STATIC'] = ALLOC_STATIC;
-Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
-Module['ALLOC_NONE'] = ALLOC_NONE;
-
-// allocate(): This is for internal use. You can use it yourself as well, but the interface
-// is a little tricky (see docs right below). The reason is that it is optimized
-// for multiple syntaxes to save space in generated code. So you should
-// normally not use allocate(), and instead allocate memory using _malloc(),
-// initialize it with setValue(), and so forth.
-// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
-// in *bytes* (note that this is sometimes confusing: the next parameter does not
-// affect this!)
-// @types: Either an array of types, one for each byte (or 0 if no type at that position),
-// or a single type which is used for the entire block. This only matters if there
-// is initial data - if @slab is a number, then this does not matter at all and is
-// ignored.
-// @allocator: How to allocate memory, see ALLOC_*
-function allocate(slab, types, allocator, ptr) {
- var zeroinit, size;
- if (typeof slab === 'number') {
- zeroinit = true;
- size = slab;
- } else {
- zeroinit = false;
- size = slab.length;
- }
-
- var singleType = typeof types === 'string' ? types : null;
-
- var ret;
- if (allocator == ALLOC_NONE) {
- ret = ptr;
- } else {
- ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
- }
-
- if (zeroinit) {
- var ptr = ret, stop;
- assert((ret & 3) == 0);
- stop = ret + (size & ~3);
- for (; ptr < stop; ptr += 4) {
- HEAP32[((ptr)>>2)]=0;
- }
- stop = ret + size;
- while (ptr < stop) {
- HEAP8[((ptr++)|0)]=0;
- }
- return ret;
- }
-
- if (singleType === 'i8') {
- if (slab.subarray || slab.slice) {
- HEAPU8.set(slab, ret);
- } else {
- HEAPU8.set(new Uint8Array(slab), ret);
- }
- return ret;
- }
-
- var i = 0, type, typeSize, previousType;
- while (i < size) {
- var curr = slab[i];
-
- if (typeof curr === 'function') {
- curr = Runtime.getFunctionIndex(curr);
- }
-
- type = singleType || types[i];
- if (type === 0) {
- i++;
- continue;
- }
-
- if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
-
- setValue(ret+i, curr, type);
-
- // no need to look up size unless type changes, so cache it
- if (previousType !== type) {
- typeSize = Runtime.getNativeTypeSize(type);
- previousType = type;
- }
- i += typeSize;
- }
-
- return ret;
-}
-Module['allocate'] = allocate;
-
-function Pointer_stringify(ptr, /* optional */ length) {
- // TODO: use TextDecoder
- // Find the length, and check for UTF while doing so
- var hasUtf = false;
- var t;
- var i = 0;
- while (1) {
- t = HEAPU8[(((ptr)+(i))|0)];
- if (t >= 128) hasUtf = true;
- else if (t == 0 && !length) break;
- i++;
- if (length && i == length) break;
- }
- if (!length) length = i;
-
- var ret = '';
-
- if (!hasUtf) {
- var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
- var curr;
- while (length > 0) {
- curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
- ret = ret ? ret + curr : curr;
- ptr += MAX_CHUNK;
- length -= MAX_CHUNK;
- }
- return ret;
- }
-
- var utf8 = new Runtime.UTF8Processor();
- for (i = 0; i < length; i++) {
- t = HEAPU8[(((ptr)+(i))|0)];
- ret += utf8.processCChar(t);
- }
- return ret;
-}
-Module['Pointer_stringify'] = Pointer_stringify;
-
-// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
-// a copy of that string as a Javascript String object.
-function UTF16ToString(ptr) {
- var i = 0;
-
- var str = '';
- while (1) {
- var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
- if (codeUnit == 0)
- return str;
- ++i;
- // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
- str += String.fromCharCode(codeUnit);
- }
-}
-Module['UTF16ToString'] = UTF16ToString;
-
-// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
-// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
-function stringToUTF16(str, outPtr) {
- for(var i = 0; i < str.length; ++i) {
- // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
- var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
- HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
- }
- // Null-terminate the pointer to the HEAP.
- HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
-}
-Module['stringToUTF16'] = stringToUTF16;
-
-// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
-// a copy of that string as a Javascript String object.
-function UTF32ToString(ptr) {
- var i = 0;
-
- var str = '';
- while (1) {
- var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
- if (utf32 == 0)
- return str;
- ++i;
- // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
- if (utf32 >= 0x10000) {
- var ch = utf32 - 0x10000;
- str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
- } else {
- str += String.fromCharCode(utf32);
- }
- }
-}
-Module['UTF32ToString'] = UTF32ToString;
-
-// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
-// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
-// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
-function stringToUTF32(str, outPtr) {
- var iChar = 0;
- for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
- // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
- var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
- if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
- var trailSurrogate = str.charCodeAt(++iCodeUnit);
- codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
- }
- HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
- ++iChar;
- }
- // Null-terminate the pointer to the HEAP.
- HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
-}
-Module['stringToUTF32'] = stringToUTF32;
-
-function demangle(func) {
- var i = 3;
- // params, etc.
- var basicTypes = {
- 'v': 'void',
- 'b': 'bool',
- 'c': 'char',
- 's': 'short',
- 'i': 'int',
- 'l': 'long',
- 'f': 'float',
- 'd': 'double',
- 'w': 'wchar_t',
- 'a': 'signed char',
- 'h': 'unsigned char',
- 't': 'unsigned short',
- 'j': 'unsigned int',
- 'm': 'unsigned long',
- 'x': 'long long',
- 'y': 'unsigned long long',
- 'z': '...'
- };
- var subs = [];
- var first = true;
- function dump(x) {
- //return;
- if (x) Module.print(x);
- Module.print(func);
- var pre = '';
- for (var a = 0; a < i; a++) pre += ' ';
- Module.print (pre + '^');
- }
- function parseNested() {
- i++;
- if (func[i] === 'K') i++; // ignore const
- var parts = [];
- while (func[i] !== 'E') {
- if (func[i] === 'S') { // substitution
- i++;
- var next = func.indexOf('_', i);
- var num = func.substring(i, next) || 0;
- parts.push(subs[num] || '?');
- i = next+1;
- continue;
- }
- if (func[i] === 'C') { // constructor
- parts.push(parts[parts.length-1]);
- i += 2;
- continue;
- }
- var size = parseInt(func.substr(i));
- var pre = size.toString().length;
- if (!size || !pre) { i--; break; } // counter i++ below us
- var curr = func.substr(i + pre, size);
- parts.push(curr);
- subs.push(curr);
- i += pre + size;
- }
- i++; // skip E
- return parts;
- }
- function parse(rawList, limit, allowVoid) { // main parser
- limit = limit || Infinity;
- var ret = '', list = [];
- function flushList() {
- return '(' + list.join(', ') + ')';
- }
- var name;
- if (func[i] === 'N') {
- // namespaced N-E
- name = parseNested().join('::');
- limit--;
- if (limit === 0) return rawList ? [name] : name;
- } else {
- // not namespaced
- if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
- var size = parseInt(func.substr(i));
- if (size) {
- var pre = size.toString().length;
- name = func.substr(i + pre, size);
- i += pre + size;
- }
- }
- first = false;
- if (func[i] === 'I') {
- i++;
- var iList = parse(true);
- var iRet = parse(true, 1, true);
- ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
- } else {
- ret = name;
- }
- paramLoop: while (i < func.length && limit-- > 0) {
- //dump('paramLoop');
- var c = func[i++];
- if (c in basicTypes) {
- list.push(basicTypes[c]);
- } else {
- switch (c) {
- case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
- case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
- case 'L': { // literal
- i++; // skip basic type
- var end = func.indexOf('E', i);
- var size = end - i;
- list.push(func.substr(i, size));
- i += size + 2; // size + 'EE'
- break;
- }
- case 'A': { // array
- var size = parseInt(func.substr(i));
- i += size.toString().length;
- if (func[i] !== '_') throw '?';
- i++; // skip _
- list.push(parse(true, 1, true)[0] + ' [' + size + ']');
- break;
- }
- case 'E': break paramLoop;
- default: ret += '?' + c; break paramLoop;
- }
- }
- }
- if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
- return rawList ? list : ret + flushList();
- }
- try {
- // Special-case the entry point, since its name differs from other name mangling.
- if (func == 'Object._main' || func == '_main') {
- return 'main()';
- }
- if (typeof func === 'number') func = Pointer_stringify(func);
- if (func[0] !== '_') return func;
- if (func[1] !== '_') return func; // C function
- if (func[2] !== 'Z') return func;
- switch (func[3]) {
- case 'n': return 'operator new()';
- case 'd': return 'operator delete()';
- }
- return parse();
- } catch(e) {
- return func;
- }
-}
-
-function demangleAll(text) {
- return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
-}
-
-function stackTrace() {
- var stack = new Error().stack;
- return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
-}
-
-// Memory management
-
-var PAGE_SIZE = 4096;
-function alignMemoryPage(x) {
- return (x+4095)&-4096;
-}
-
-var HEAP;
-var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
-
-var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
-var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
-var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
-
-function enlargeMemory() {
- abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
-}
-
-var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
-var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 16777216;
-var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
-
-var totalMemory = 4096;
-while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
- if (totalMemory < 16*1024*1024) {
- totalMemory *= 2;
- } else {
- totalMemory += 16*1024*1024
- }
-}
-if (totalMemory !== TOTAL_MEMORY) {
- Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
- TOTAL_MEMORY = totalMemory;
-}
-
-// Initialize the runtime's memory
-// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
-assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
- 'JS engine does not provide full typed array support');
-
-var buffer = new ArrayBuffer(TOTAL_MEMORY);
-HEAP8 = new Int8Array(buffer);
-HEAP16 = new Int16Array(buffer);
-HEAP32 = new Int32Array(buffer);
-HEAPU8 = new Uint8Array(buffer);
-HEAPU16 = new Uint16Array(buffer);
-HEAPU32 = new Uint32Array(buffer);
-HEAPF32 = new Float32Array(buffer);
-HEAPF64 = new Float64Array(buffer);
-
-// Endianness check (note: assumes compiler arch was little-endian)
-HEAP32[0] = 255;
-assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
-
-Module['HEAP'] = HEAP;
-Module['HEAP8'] = HEAP8;
-Module['HEAP16'] = HEAP16;
-Module['HEAP32'] = HEAP32;
-Module['HEAPU8'] = HEAPU8;
-Module['HEAPU16'] = HEAPU16;
-Module['HEAPU32'] = HEAPU32;
-Module['HEAPF32'] = HEAPF32;
-Module['HEAPF64'] = HEAPF64;
-
-function callRuntimeCallbacks(callbacks) {
- while(callbacks.length > 0) {
- var callback = callbacks.shift();
- if (typeof callback == 'function') {
- callback();
- continue;
- }
- var func = callback.func;
- if (typeof func === 'number') {
- if (callback.arg === undefined) {
- Runtime.dynCall('v', func);
- } else {
- Runtime.dynCall('vi', func, [callback.arg]);
- }
- } else {
- func(callback.arg === undefined ? null : callback.arg);
- }
- }
-}
-
-var __ATPRERUN__ = []; // functions called before the runtime is initialized
-var __ATINIT__ = []; // functions called during startup
-var __ATMAIN__ = []; // functions called when main() is to be run
-var __ATEXIT__ = []; // functions called during shutdown
-var __ATPOSTRUN__ = []; // functions called after the runtime has exited
-
-var runtimeInitialized = false;
-
-function preRun() {
- // compatibility - merge in anything from Module['preRun'] at this time
- if (Module['preRun']) {
- if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
- while (Module['preRun'].length) {
- addOnPreRun(Module['preRun'].shift());
- }
- }
- callRuntimeCallbacks(__ATPRERUN__);
-}
-
-function ensureInitRuntime() {
- if (runtimeInitialized) return;
- runtimeInitialized = true;
- callRuntimeCallbacks(__ATINIT__);
-}
-
-function preMain() {
- callRuntimeCallbacks(__ATMAIN__);
-}
-
-function exitRuntime() {
- callRuntimeCallbacks(__ATEXIT__);
-}
-
-function postRun() {
- // compatibility - merge in anything from Module['postRun'] at this time
- if (Module['postRun']) {
- if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
- while (Module['postRun'].length) {
- addOnPostRun(Module['postRun'].shift());
- }
- }
- callRuntimeCallbacks(__ATPOSTRUN__);
-}
-
-function addOnPreRun(cb) {
- __ATPRERUN__.unshift(cb);
-}
-Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
-
-function addOnInit(cb) {
- __ATINIT__.unshift(cb);
-}
-Module['addOnInit'] = Module.addOnInit = addOnInit;
-
-function addOnPreMain(cb) {
- __ATMAIN__.unshift(cb);
-}
-Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
-
-function addOnExit(cb) {
- __ATEXIT__.unshift(cb);
-}
-Module['addOnExit'] = Module.addOnExit = addOnExit;
-
-function addOnPostRun(cb) {
- __ATPOSTRUN__.unshift(cb);
-}
-Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
-
-// Tools
-
-// This processes a JS string into a C-line array of numbers, 0-terminated.
-// For LLVM-originating strings, see parser.js:parseLLVMString function
-function intArrayFromString(stringy, dontAddNull, length /* optional */) {
- var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
- if (length) {
- ret.length = length;
- }
- if (!dontAddNull) {
- ret.push(0);
- }
- return ret;
-}
-Module['intArrayFromString'] = intArrayFromString;
-
-function intArrayToString(array) {
- var ret = [];
- for (var i = 0; i < array.length; i++) {
- var chr = array[i];
- if (chr > 0xFF) {
- chr &= 0xFF;
- }
- ret.push(String.fromCharCode(chr));
- }
- return ret.join('');
-}
-Module['intArrayToString'] = intArrayToString;
-
-// Write a Javascript array to somewhere in the heap
-function writeStringToMemory(string, buffer, dontAddNull) {
- var array = intArrayFromString(string, dontAddNull);
- var i = 0;
- while (i < array.length) {
- var chr = array[i];
- HEAP8[(((buffer)+(i))|0)]=chr;
- i = i + 1;
- }
-}
-Module['writeStringToMemory'] = writeStringToMemory;
-
-function writeArrayToMemory(array, buffer) {
- for (var i = 0; i < array.length; i++) {
- HEAP8[(((buffer)+(i))|0)]=array[i];
- }
-}
-Module['writeArrayToMemory'] = writeArrayToMemory;
-
-function writeAsciiToMemory(str, buffer, dontAddNull) {
- for (var i = 0; i < str.length; i++) {
- HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
- }
- if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
-}
-Module['writeAsciiToMemory'] = writeAsciiToMemory;
-
-function unSign(value, bits, ignore) {
- if (value >= 0) {
- return value;
- }
- return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
- : Math.pow(2, bits) + value;
-}
-function reSign(value, bits, ignore) {
- if (value <= 0) {
- return value;
- }
- var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
- : Math.pow(2, bits-1);
- if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
- // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
- // TODO: In i64 mode 1, resign the two parts separately and safely
- value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
- }
- return value;
-}
-
-// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
-if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
- var ah = a >>> 16;
- var al = a & 0xffff;
- var bh = b >>> 16;
- var bl = b & 0xffff;
- return (al*bl + ((ah*bl + al*bh) << 16))|0;
-};
-Math.imul = Math['imul'];
-
-
-var Math_abs = Math.abs;
-var Math_cos = Math.cos;
-var Math_sin = Math.sin;
-var Math_tan = Math.tan;
-var Math_acos = Math.acos;
-var Math_asin = Math.asin;
-var Math_atan = Math.atan;
-var Math_atan2 = Math.atan2;
-var Math_exp = Math.exp;
-var Math_log = Math.log;
-var Math_sqrt = Math.sqrt;
-var Math_ceil = Math.ceil;
-var Math_floor = Math.floor;
-var Math_pow = Math.pow;
-var Math_imul = Math.imul;
-var Math_fround = Math.fround;
-var Math_min = Math.min;
-
-// A counter of dependencies for calling run(). If we need to
-// do asynchronous work before running, increment this and
-// decrement it. Incrementing must happen in a place like
-// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
-// Note that you can add dependencies in preRun, even though
-// it happens right before run - run will be postponed until
-// the dependencies are met.
-var runDependencies = 0;
-var runDependencyWatcher = null;
-var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
-
-function addRunDependency(id) {
- runDependencies++;
- if (Module['monitorRunDependencies']) {
- Module['monitorRunDependencies'](runDependencies);
- }
-}
-Module['addRunDependency'] = addRunDependency;
-function removeRunDependency(id) {
- runDependencies--;
- if (Module['monitorRunDependencies']) {
- Module['monitorRunDependencies'](runDependencies);
- }
- if (runDependencies == 0) {
- if (runDependencyWatcher !== null) {
- clearInterval(runDependencyWatcher);
- runDependencyWatcher = null;
- }
- if (dependenciesFulfilled) {
- var callback = dependenciesFulfilled;
- dependenciesFulfilled = null;
- callback(); // can add another dependenciesFulfilled
- }
- }
-}
-Module['removeRunDependency'] = removeRunDependency;
-
-Module["preloadedImages"] = {}; // maps url to image data
-Module["preloadedAudios"] = {}; // maps url to audio data
-
-
-var memoryInitializer = null;
-
-// === Body ===
-
-
-
-
-
-STATIC_BASE = 8;
-
-STATICTOP = STATIC_BASE + Runtime.alignMemory(20195);
-/* global initializers */ __ATINIT__.push();
-
-
-/* memory initializer */ allocate([], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
-
-
-
-
-var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
-
-assert(tempDoublePtr % 8 == 0);
-
-function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
-
- HEAP8[tempDoublePtr] = HEAP8[ptr];
-
- HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
-
- HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
-
- HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
-
-}
-
-function copyTempDouble(ptr) {
-
- HEAP8[tempDoublePtr] = HEAP8[ptr];
-
- HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
-
- HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
-
- HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
-
- HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
-
- HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
-
- HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
-
- HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
-
-}
-
-
- function _malloc(bytes) {
- /* Over-allocate to make sure it is byte-aligned by 8.
- * This will leak memory, but this is only the dummy
- * implementation (replaced by dlmalloc normally) so
- * not an issue.
- */
- var ptr = Runtime.dynamicAlloc(bytes + 8);
- return (ptr+8) & 0xFFFFFFF8;
- }
- Module["_malloc"] = _malloc;
-
-
-
-
- var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
-
- var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
-
-
- var ___errno_state=0;function ___setErrNo(value) {
- // For convenient setting and returning of errno.
- HEAP32[((___errno_state)>>2)]=value;
- return value;
- }
-
- var TTY={ttys:[],init:function () {
- // https://github.com/kripken/emscripten/pull/1555
- // if (ENVIRONMENT_IS_NODE) {
- // // currently, FS.init does not distinguish if process.stdin is a file or TTY
- // // device, it always assumes it's a TTY device. because of this, we're forcing
- // // process.stdin to UTF8 encoding to at least make stdin reading compatible
- // // with text files until FS.init can be refactored.
- // process['stdin']['setEncoding']('utf8');
- // }
- },shutdown:function () {
- // https://github.com/kripken/emscripten/pull/1555
- // if (ENVIRONMENT_IS_NODE) {
- // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
- // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
- // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
- // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
- // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
- // process['stdin']['pause']();
- // }
- },register:function (dev, ops) {
- TTY.ttys[dev] = { input: [], output: [], ops: ops };
- FS.registerDevice(dev, TTY.stream_ops);
- },stream_ops:{open:function (stream) {
- var tty = TTY.ttys[stream.node.rdev];
- if (!tty) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- stream.tty = tty;
- stream.seekable = false;
- },close:function (stream) {
- // flush any pending line data
- if (stream.tty.output.length) {
- stream.tty.ops.put_char(stream.tty, 10);
- }
- },read:function (stream, buffer, offset, length, pos /* ignored */) {
- if (!stream.tty || !stream.tty.ops.get_char) {
- throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
- }
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = stream.tty.ops.get_char(stream.tty);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset+i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- },write:function (stream, buffer, offset, length, pos) {
- if (!stream.tty || !stream.tty.ops.put_char) {
- throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
- }
- for (var i = 0; i < length; i++) {
- try {
- stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- }},default_tty_ops:{get_char:function (tty) {
- if (!tty.input.length) {
- var result = null;
- if (ENVIRONMENT_IS_NODE) {
- result = process['stdin']['read']();
- if (!result) {
- if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
- return null; // EOF
- }
- return undefined; // no data available
- }
- } else if (typeof window != 'undefined' &&
- typeof window.prompt == 'function') {
- // Browser.
- result = window.prompt('Input: '); // returns null on cancel
- if (result !== null) {
- result += '\n';
- }
- } else if (typeof readline == 'function') {
- // Command line.
- result = readline();
- if (result !== null) {
- result += '\n';
- }
- }
- if (!result) {
- return null;
- }
- tty.input = intArrayFromString(result, true);
- }
- return tty.input.shift();
- },put_char:function (tty, val) {
- if (val === null || val === 10) {
- Module['print'](tty.output.join(''));
- tty.output = [];
- } else {
- tty.output.push(TTY.utf8.processCChar(val));
- }
- }},default_tty1_ops:{put_char:function (tty, val) {
- if (val === null || val === 10) {
- Module['printErr'](tty.output.join(''));
- tty.output = [];
- } else {
- tty.output.push(TTY.utf8.processCChar(val));
- }
- }}};
-
- var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
- return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
- },createNode:function (parent, name, mode, dev) {
- if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
- // no supported
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (!MEMFS.ops_table) {
- MEMFS.ops_table = {
- dir: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr,
- lookup: MEMFS.node_ops.lookup,
- mknod: MEMFS.node_ops.mknod,
- rename: MEMFS.node_ops.rename,
- unlink: MEMFS.node_ops.unlink,
- rmdir: MEMFS.node_ops.rmdir,
- readdir: MEMFS.node_ops.readdir,
- symlink: MEMFS.node_ops.symlink
- },
- stream: {
- llseek: MEMFS.stream_ops.llseek
- }
- },
- file: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr
- },
- stream: {
- llseek: MEMFS.stream_ops.llseek,
- read: MEMFS.stream_ops.read,
- write: MEMFS.stream_ops.write,
- allocate: MEMFS.stream_ops.allocate,
- mmap: MEMFS.stream_ops.mmap
- }
- },
- link: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr,
- readlink: MEMFS.node_ops.readlink
- },
- stream: {}
- },
- chrdev: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr
- },
- stream: FS.chrdev_stream_ops
- },
- };
- }
- var node = FS.createNode(parent, name, mode, dev);
- if (FS.isDir(node.mode)) {
- node.node_ops = MEMFS.ops_table.dir.node;
- node.stream_ops = MEMFS.ops_table.dir.stream;
- node.contents = {};
- } else if (FS.isFile(node.mode)) {
- node.node_ops = MEMFS.ops_table.file.node;
- node.stream_ops = MEMFS.ops_table.file.stream;
- node.contents = [];
- node.contentMode = MEMFS.CONTENT_FLEXIBLE;
- } else if (FS.isLink(node.mode)) {
- node.node_ops = MEMFS.ops_table.link.node;
- node.stream_ops = MEMFS.ops_table.link.stream;
- } else if (FS.isChrdev(node.mode)) {
- node.node_ops = MEMFS.ops_table.chrdev.node;
- node.stream_ops = MEMFS.ops_table.chrdev.stream;
- }
- node.timestamp = Date.now();
- // add the new node to the parent
- if (parent) {
- parent.contents[name] = node;
- }
- return node;
- },ensureFlexible:function (node) {
- if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
- var contents = node.contents;
- node.contents = Array.prototype.slice.call(contents);
- node.contentMode = MEMFS.CONTENT_FLEXIBLE;
- }
- },node_ops:{getattr:function (node) {
- var attr = {};
- // device numbers reuse inode numbers.
- attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
- attr.ino = node.id;
- attr.mode = node.mode;
- attr.nlink = 1;
- attr.uid = 0;
- attr.gid = 0;
- attr.rdev = node.rdev;
- if (FS.isDir(node.mode)) {
- attr.size = 4096;
- } else if (FS.isFile(node.mode)) {
- attr.size = node.contents.length;
- } else if (FS.isLink(node.mode)) {
- attr.size = node.link.length;
- } else {
- attr.size = 0;
- }
- attr.atime = new Date(node.timestamp);
- attr.mtime = new Date(node.timestamp);
- attr.ctime = new Date(node.timestamp);
- // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
- // but this is not required by the standard.
- attr.blksize = 4096;
- attr.blocks = Math.ceil(attr.size / attr.blksize);
- return attr;
- },setattr:function (node, attr) {
- if (attr.mode !== undefined) {
- node.mode = attr.mode;
- }
- if (attr.timestamp !== undefined) {
- node.timestamp = attr.timestamp;
- }
- if (attr.size !== undefined) {
- MEMFS.ensureFlexible(node);
- var contents = node.contents;
- if (attr.size < contents.length) contents.length = attr.size;
- else while (attr.size > contents.length) contents.push(0);
- }
- },lookup:function (parent, name) {
- throw FS.genericErrors[ERRNO_CODES.ENOENT];
- },mknod:function (parent, name, mode, dev) {
- return MEMFS.createNode(parent, name, mode, dev);
- },rename:function (old_node, new_dir, new_name) {
- // if we're overwriting a directory at new_name, make sure it's empty.
- if (FS.isDir(old_node.mode)) {
- var new_node;
- try {
- new_node = FS.lookupNode(new_dir, new_name);
- } catch (e) {
- }
- if (new_node) {
- for (var i in new_node.contents) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- }
- }
- // do the internal rewiring
- delete old_node.parent.contents[old_node.name];
- old_node.name = new_name;
- new_dir.contents[new_name] = old_node;
- old_node.parent = new_dir;
- },unlink:function (parent, name) {
- delete parent.contents[name];
- },rmdir:function (parent, name) {
- var node = FS.lookupNode(parent, name);
- for (var i in node.contents) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- delete parent.contents[name];
- },readdir:function (node) {
- var entries = ['.', '..']
- for (var key in node.contents) {
- if (!node.contents.hasOwnProperty(key)) {
- continue;
- }
- entries.push(key);
- }
- return entries;
- },symlink:function (parent, newname, oldpath) {
- var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
- node.link = oldpath;
- return node;
- },readlink:function (node) {
- if (!FS.isLink(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return node.link;
- }},stream_ops:{read:function (stream, buffer, offset, length, position) {
- var contents = stream.node.contents;
- if (position >= contents.length)
- return 0;
- var size = Math.min(contents.length - position, length);
- assert(size >= 0);
- if (size > 8 && contents.subarray) { // non-trivial, and typed array
- buffer.set(contents.subarray(position, position + size), offset);
- } else
- {
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents[position + i];
- }
- }
- return size;
- },write:function (stream, buffer, offset, length, position, canOwn) {
- var node = stream.node;
- node.timestamp = Date.now();
- var contents = node.contents;
- if (length && contents.length === 0 && position === 0 && buffer.subarray) {
- // just replace it with the new data
- if (canOwn && offset === 0) {
- node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
- node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
- } else {
- node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
- node.contentMode = MEMFS.CONTENT_FIXED;
- }
- return length;
- }
- MEMFS.ensureFlexible(node);
- var contents = node.contents;
- while (contents.length < position) contents.push(0);
- for (var i = 0; i < length; i++) {
- contents[position + i] = buffer[offset + i];
- }
- return length;
- },llseek:function (stream, offset, whence) {
- var position = offset;
- if (whence === 1) { // SEEK_CUR.
- position += stream.position;
- } else if (whence === 2) { // SEEK_END.
- if (FS.isFile(stream.node.mode)) {
- position += stream.node.contents.length;
- }
- }
- if (position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- stream.ungotten = [];
- stream.position = position;
- return position;
- },allocate:function (stream, offset, length) {
- MEMFS.ensureFlexible(stream.node);
- var contents = stream.node.contents;
- var limit = offset + length;
- while (limit > contents.length) contents.push(0);
- },mmap:function (stream, buffer, offset, length, position, prot, flags) {
- if (!FS.isFile(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- var ptr;
- var allocated;
- var contents = stream.node.contents;
- // Only make a new copy when MAP_PRIVATE is specified.
- if ( !(flags & 2) &&
- (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
- // We can't emulate MAP_SHARED when the file is not backed by the buffer
- // we're mapping to (e.g. the HEAP buffer).
- allocated = false;
- ptr = contents.byteOffset;
- } else {
- // Try to avoid unnecessary slices.
- if (position > 0 || position + length < contents.length) {
- if (contents.subarray) {
- contents = contents.subarray(position, position + length);
- } else {
- contents = Array.prototype.slice.call(contents, position, position + length);
- }
- }
- allocated = true;
- ptr = _malloc(length);
- if (!ptr) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
- }
- buffer.set(contents, ptr);
- }
- return { ptr: ptr, allocated: allocated };
- }}};
-
- var IDBFS={dbs:{},indexedDB:function () {
- return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
- },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
- // reuse all of the core MEMFS functionality
- return MEMFS.mount.apply(null, arguments);
- },syncfs:function (mount, populate, callback) {
- IDBFS.getLocalSet(mount, function(err, local) {
- if (err) return callback(err);
-
- IDBFS.getRemoteSet(mount, function(err, remote) {
- if (err) return callback(err);
-
- var src = populate ? remote : local;
- var dst = populate ? local : remote;
-
- IDBFS.reconcile(src, dst, callback);
- });
- });
- },getDB:function (name, callback) {
- // check the cache first
- var db = IDBFS.dbs[name];
- if (db) {
- return callback(null, db);
- }
-
- var req;
- try {
- req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
- } catch (e) {
- return callback(e);
- }
- req.onupgradeneeded = function(e) {
- var db = e.target.result;
- var transaction = e.target.transaction;
-
- var fileStore;
-
- if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
- fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
- } else {
- fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
- }
-
- fileStore.createIndex('timestamp', 'timestamp', { unique: false });
- };
- req.onsuccess = function() {
- db = req.result;
-
- // add to the cache
- IDBFS.dbs[name] = db;
- callback(null, db);
- };
- req.onerror = function() {
- callback(this.error);
- };
- },getLocalSet:function (mount, callback) {
- var entries = {};
-
- function isRealDir(p) {
- return p !== '.' && p !== '..';
- };
- function toAbsolute(root) {
- return function(p) {
- return PATH.join2(root, p);
- }
- };
-
- var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
-
- while (check.length) {
- var path = check.pop();
- var stat;
-
- try {
- stat = FS.stat(path);
- } catch (e) {
- return callback(e);
- }
-
- if (FS.isDir(stat.mode)) {
- check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
- }
-
- entries[path] = { timestamp: stat.mtime };
- }
-
- return callback(null, { type: 'local', entries: entries });
- },getRemoteSet:function (mount, callback) {
- var entries = {};
-
- IDBFS.getDB(mount.mountpoint, function(err, db) {
- if (err) return callback(err);
-
- var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
- transaction.onerror = function() { callback(this.error); };
-
- var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
- var index = store.index('timestamp');
-
- index.openKeyCursor().onsuccess = function(event) {
- var cursor = event.target.result;
-
- if (!cursor) {
- return callback(null, { type: 'remote', db: db, entries: entries });
- }
-
- entries[cursor.primaryKey] = { timestamp: cursor.key };
-
- cursor.continue();
- };
- });
- },loadLocalEntry:function (path, callback) {
- var stat, node;
-
- try {
- var lookup = FS.lookupPath(path);
- node = lookup.node;
- stat = FS.stat(path);
- } catch (e) {
- return callback(e);
- }
-
- if (FS.isDir(stat.mode)) {
- return callback(null, { timestamp: stat.mtime, mode: stat.mode });
- } else if (FS.isFile(stat.mode)) {
- return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
- } else {
- return callback(new Error('node type not supported'));
- }
- },storeLocalEntry:function (path, entry, callback) {
- try {
- if (FS.isDir(entry.mode)) {
- FS.mkdir(path, entry.mode);
- } else if (FS.isFile(entry.mode)) {
- FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
- } else {
- return callback(new Error('node type not supported'));
- }
-
- FS.utime(path, entry.timestamp, entry.timestamp);
- } catch (e) {
- return callback(e);
- }
-
- callback(null);
- },removeLocalEntry:function (path, callback) {
- try {
- var lookup = FS.lookupPath(path);
- var stat = FS.stat(path);
-
- if (FS.isDir(stat.mode)) {
- FS.rmdir(path);
- } else if (FS.isFile(stat.mode)) {
- FS.unlink(path);
- }
- } catch (e) {
- return callback(e);
- }
-
- callback(null);
- },loadRemoteEntry:function (store, path, callback) {
- var req = store.get(path);
- req.onsuccess = function(event) { callback(null, event.target.result); };
- req.onerror = function() { callback(this.error); };
- },storeRemoteEntry:function (store, path, entry, callback) {
- var req = store.put(entry, path);
- req.onsuccess = function() { callback(null); };
- req.onerror = function() { callback(this.error); };
- },removeRemoteEntry:function (store, path, callback) {
- var req = store.delete(path);
- req.onsuccess = function() { callback(null); };
- req.onerror = function() { callback(this.error); };
- },reconcile:function (src, dst, callback) {
- var total = 0;
-
- var create = [];
- Object.keys(src.entries).forEach(function (key) {
- var e = src.entries[key];
- var e2 = dst.entries[key];
- if (!e2 || e.timestamp > e2.timestamp) {
- create.push(key);
- total++;
- }
- });
-
- var remove = [];
- Object.keys(dst.entries).forEach(function (key) {
- var e = dst.entries[key];
- var e2 = src.entries[key];
- if (!e2) {
- remove.push(key);
- total++;
- }
- });
-
- if (!total) {
- return callback(null);
- }
-
- var errored = false;
- var completed = 0;
- var db = src.type === 'remote' ? src.db : dst.db;
- var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
- var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
-
- function done(err) {
- if (err) {
- if (!done.errored) {
- done.errored = true;
- return callback(err);
- }
- return;
- }
- if (++completed >= total) {
- return callback(null);
- }
- };
-
- transaction.onerror = function() { done(this.error); };
-
- // sort paths in ascending order so directory entries are created
- // before the files inside them
- create.sort().forEach(function (path) {
- if (dst.type === 'local') {
- IDBFS.loadRemoteEntry(store, path, function (err, entry) {
- if (err) return done(err);
- IDBFS.storeLocalEntry(path, entry, done);
- });
- } else {
- IDBFS.loadLocalEntry(path, function (err, entry) {
- if (err) return done(err);
- IDBFS.storeRemoteEntry(store, path, entry, done);
- });
- }
- });
-
- // sort paths in descending order so files are deleted before their
- // parent directories
- remove.sort().reverse().forEach(function(path) {
- if (dst.type === 'local') {
- IDBFS.removeLocalEntry(path, done);
- } else {
- IDBFS.removeRemoteEntry(store, path, done);
- }
- });
- }};
-
- var NODEFS={isWindows:false,staticInit:function () {
- NODEFS.isWindows = !!process.platform.match(/^win/);
- },mount:function (mount) {
- assert(ENVIRONMENT_IS_NODE);
- return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
- },createNode:function (parent, name, mode, dev) {
- if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var node = FS.createNode(parent, name, mode);
- node.node_ops = NODEFS.node_ops;
- node.stream_ops = NODEFS.stream_ops;
- return node;
- },getMode:function (path) {
- var stat;
- try {
- stat = fs.lstatSync(path);
- if (NODEFS.isWindows) {
- // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
- // propagate write bits to execute bits.
- stat.mode = stat.mode | ((stat.mode & 146) >> 1);
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- return stat.mode;
- },realPath:function (node) {
- var parts = [];
- while (node.parent !== node) {
- parts.push(node.name);
- node = node.parent;
- }
- parts.push(node.mount.opts.root);
- parts.reverse();
- return PATH.join.apply(null, parts);
- },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
- if (flags in NODEFS.flagsToPermissionStringMap) {
- return NODEFS.flagsToPermissionStringMap[flags];
- } else {
- return flags;
- }
- },node_ops:{getattr:function (node) {
- var path = NODEFS.realPath(node);
- var stat;
- try {
- stat = fs.lstatSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
- // See http://support.microsoft.com/kb/140365
- if (NODEFS.isWindows && !stat.blksize) {
- stat.blksize = 4096;
- }
- if (NODEFS.isWindows && !stat.blocks) {
- stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
- }
- return {
- dev: stat.dev,
- ino: stat.ino,
- mode: stat.mode,
- nlink: stat.nlink,
- uid: stat.uid,
- gid: stat.gid,
- rdev: stat.rdev,
- size: stat.size,
- atime: stat.atime,
- mtime: stat.mtime,
- ctime: stat.ctime,
- blksize: stat.blksize,
- blocks: stat.blocks
- };
- },setattr:function (node, attr) {
- var path = NODEFS.realPath(node);
- try {
- if (attr.mode !== undefined) {
- fs.chmodSync(path, attr.mode);
- // update the common node structure mode as well
- node.mode = attr.mode;
- }
- if (attr.timestamp !== undefined) {
- var date = new Date(attr.timestamp);
- fs.utimesSync(path, date, date);
- }
- if (attr.size !== undefined) {
- fs.truncateSync(path, attr.size);
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },lookup:function (parent, name) {
- var path = PATH.join2(NODEFS.realPath(parent), name);
- var mode = NODEFS.getMode(path);
- return NODEFS.createNode(parent, name, mode);
- },mknod:function (parent, name, mode, dev) {
- var node = NODEFS.createNode(parent, name, mode, dev);
- // create the backing node for this in the fs root as well
- var path = NODEFS.realPath(node);
- try {
- if (FS.isDir(node.mode)) {
- fs.mkdirSync(path, node.mode);
- } else {
- fs.writeFileSync(path, '', { mode: node.mode });
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- return node;
- },rename:function (oldNode, newDir, newName) {
- var oldPath = NODEFS.realPath(oldNode);
- var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
- try {
- fs.renameSync(oldPath, newPath);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },unlink:function (parent, name) {
- var path = PATH.join2(NODEFS.realPath(parent), name);
- try {
- fs.unlinkSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },rmdir:function (parent, name) {
- var path = PATH.join2(NODEFS.realPath(parent), name);
- try {
- fs.rmdirSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },readdir:function (node) {
- var path = NODEFS.realPath(node);
- try {
- return fs.readdirSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },symlink:function (parent, newName, oldPath) {
- var newPath = PATH.join2(NODEFS.realPath(parent), newName);
- try {
- fs.symlinkSync(oldPath, newPath);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },readlink:function (node) {
- var path = NODEFS.realPath(node);
- try {
- return fs.readlinkSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }},stream_ops:{open:function (stream) {
- var path = NODEFS.realPath(stream.node);
- try {
- if (FS.isFile(stream.node.mode)) {
- stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },close:function (stream) {
- try {
- if (FS.isFile(stream.node.mode) && stream.nfd) {
- fs.closeSync(stream.nfd);
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- },read:function (stream, buffer, offset, length, position) {
- // FIXME this is terrible.
- var nbuffer = new Buffer(length);
- var res;
- try {
- res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- if (res > 0) {
- for (var i = 0; i < res; i++) {
- buffer[offset + i] = nbuffer[i];
- }
- }
- return res;
- },write:function (stream, buffer, offset, length, position) {
- // FIXME this is terrible.
- var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
- var res;
- try {
- res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- return res;
- },llseek:function (stream, offset, whence) {
- var position = offset;
- if (whence === 1) { // SEEK_CUR.
- position += stream.position;
- } else if (whence === 2) { // SEEK_END.
- if (FS.isFile(stream.node.mode)) {
- try {
- var stat = fs.fstatSync(stream.nfd);
- position += stat.size;
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }
- }
-
- if (position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
-
- stream.position = position;
- return position;
- }}};
-
- var _stdin=allocate(1, "i32*", ALLOC_STATIC);
-
- var _stdout=allocate(1, "i32*", ALLOC_STATIC);
-
- var _stderr=allocate(1, "i32*", ALLOC_STATIC);
-
- function _fflush(stream) {
- // int fflush(FILE *stream);
- // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
- // we don't currently perform any user-space buffering of data
- }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
- if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
- return ___setErrNo(e.errno);
- },lookupPath:function (path, opts) {
- path = PATH.resolve(FS.cwd(), path);
- opts = opts || {};
-
- var defaults = {
- follow_mount: true,
- recurse_count: 0
- };
- for (var key in defaults) {
- if (opts[key] === undefined) {
- opts[key] = defaults[key];
- }
- }
-
- if (opts.recurse_count > 8) { // max recursive lookup of 8
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
-
- // split the path
- var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
- return !!p;
- }), false);
-
- // start at the root
- var current = FS.root;
- var current_path = '/';
-
- for (var i = 0; i < parts.length; i++) {
- var islast = (i === parts.length-1);
- if (islast && opts.parent) {
- // stop resolving
- break;
- }
-
- current = FS.lookupNode(current, parts[i]);
- current_path = PATH.join2(current_path, parts[i]);
-
- // jump to the mount's root node if this is a mountpoint
- if (FS.isMountpoint(current)) {
- if (!islast || (islast && opts.follow_mount)) {
- current = current.mounted.root;
- }
- }
-
- // by default, lookupPath will not follow a symlink if it is the final path component.
- // setting opts.follow = true will override this behavior.
- if (!islast || opts.follow) {
- var count = 0;
- while (FS.isLink(current.mode)) {
- var link = FS.readlink(current_path);
- current_path = PATH.resolve(PATH.dirname(current_path), link);
-
- var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
- current = lookup.node;
-
- if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
- }
- }
- }
-
- return { path: current_path, node: current };
- },getPath:function (node) {
- var path;
- while (true) {
- if (FS.isRoot(node)) {
- var mount = node.mount.mountpoint;
- if (!path) return mount;
- return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
- }
- path = path ? node.name + '/' + path : node.name;
- node = node.parent;
- }
- },hashName:function (parentid, name) {
- var hash = 0;
-
-
- for (var i = 0; i < name.length; i++) {
- hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
- }
- return ((parentid + hash) >>> 0) % FS.nameTable.length;
- },hashAddNode:function (node) {
- var hash = FS.hashName(node.parent.id, node.name);
- node.name_next = FS.nameTable[hash];
- FS.nameTable[hash] = node;
- },hashRemoveNode:function (node) {
- var hash = FS.hashName(node.parent.id, node.name);
- if (FS.nameTable[hash] === node) {
- FS.nameTable[hash] = node.name_next;
- } else {
- var current = FS.nameTable[hash];
- while (current) {
- if (current.name_next === node) {
- current.name_next = node.name_next;
- break;
- }
- current = current.name_next;
- }
- }
- },lookupNode:function (parent, name) {
- var err = FS.mayLookup(parent);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- var hash = FS.hashName(parent.id, name);
- for (var node = FS.nameTable[hash]; node; node = node.name_next) {
- var nodeName = node.name;
- if (node.parent.id === parent.id && nodeName === name) {
- return node;
- }
- }
- // if we failed to find it in the cache, call into the VFS
- return FS.lookup(parent, name);
- },createNode:function (parent, name, mode, rdev) {
- if (!FS.FSNode) {
- FS.FSNode = function(parent, name, mode, rdev) {
- if (!parent) {
- parent = this; // root node sets parent to itself
- }
- this.parent = parent;
- this.mount = parent.mount;
- this.mounted = null;
- this.id = FS.nextInode++;
- this.name = name;
- this.mode = mode;
- this.node_ops = {};
- this.stream_ops = {};
- this.rdev = rdev;
- };
-
- FS.FSNode.prototype = {};
-
- // compatibility
- var readMode = 292 | 73;
- var writeMode = 146;
-
- // NOTE we must use Object.defineProperties instead of individual calls to
- // Object.defineProperty in order to make closure compiler happy
- Object.defineProperties(FS.FSNode.prototype, {
- read: {
- get: function() { return (this.mode & readMode) === readMode; },
- set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
- },
- write: {
- get: function() { return (this.mode & writeMode) === writeMode; },
- set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
- },
- isFolder: {
- get: function() { return FS.isDir(this.mode); },
- },
- isDevice: {
- get: function() { return FS.isChrdev(this.mode); },
- },
- });
- }
-
- var node = new FS.FSNode(parent, name, mode, rdev);
-
- FS.hashAddNode(node);
-
- return node;
- },destroyNode:function (node) {
- FS.hashRemoveNode(node);
- },isRoot:function (node) {
- return node === node.parent;
- },isMountpoint:function (node) {
- return !!node.mounted;
- },isFile:function (mode) {
- return (mode & 61440) === 32768;
- },isDir:function (mode) {
- return (mode & 61440) === 16384;
- },isLink:function (mode) {
- return (mode & 61440) === 40960;
- },isChrdev:function (mode) {
- return (mode & 61440) === 8192;
- },isBlkdev:function (mode) {
- return (mode & 61440) === 24576;
- },isFIFO:function (mode) {
- return (mode & 61440) === 4096;
- },isSocket:function (mode) {
- return (mode & 49152) === 49152;
- },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
- var flags = FS.flagModes[str];
- if (typeof flags === 'undefined') {
- throw new Error('Unknown file open mode: ' + str);
- }
- return flags;
- },flagsToPermissionString:function (flag) {
- var accmode = flag & 2097155;
- var perms = ['r', 'w', 'rw'][accmode];
- if ((flag & 512)) {
- perms += 'w';
- }
- return perms;
- },nodePermissions:function (node, perms) {
- if (FS.ignorePermissions) {
- return 0;
- }
- // return 0 if any user, group or owner bits are set.
- if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
- return ERRNO_CODES.EACCES;
- }
- return 0;
- },mayLookup:function (dir) {
- return FS.nodePermissions(dir, 'x');
- },mayCreate:function (dir, name) {
- try {
- var node = FS.lookupNode(dir, name);
- return ERRNO_CODES.EEXIST;
- } catch (e) {
- }
- return FS.nodePermissions(dir, 'wx');
- },mayDelete:function (dir, name, isdir) {
- var node;
- try {
- node = FS.lookupNode(dir, name);
- } catch (e) {
- return e.errno;
- }
- var err = FS.nodePermissions(dir, 'wx');
- if (err) {
- return err;
- }
- if (isdir) {
- if (!FS.isDir(node.mode)) {
- return ERRNO_CODES.ENOTDIR;
- }
- if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
- return ERRNO_CODES.EBUSY;
- }
- } else {
- if (FS.isDir(node.mode)) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return 0;
- },mayOpen:function (node, flags) {
- if (!node) {
- return ERRNO_CODES.ENOENT;
- }
- if (FS.isLink(node.mode)) {
- return ERRNO_CODES.ELOOP;
- } else if (FS.isDir(node.mode)) {
- if ((flags & 2097155) !== 0 || // opening for write
- (flags & 512)) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
- },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
- fd_start = fd_start || 0;
- fd_end = fd_end || FS.MAX_OPEN_FDS;
- for (var fd = fd_start; fd <= fd_end; fd++) {
- if (!FS.streams[fd]) {
- return fd;
- }
- }
- throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
- },getStream:function (fd) {
- return FS.streams[fd];
- },createStream:function (stream, fd_start, fd_end) {
- if (!FS.FSStream) {
- FS.FSStream = function(){};
- FS.FSStream.prototype = {};
- // compatibility
- Object.defineProperties(FS.FSStream.prototype, {
- object: {
- get: function() { return this.node; },
- set: function(val) { this.node = val; }
- },
- isRead: {
- get: function() { return (this.flags & 2097155) !== 1; }
- },
- isWrite: {
- get: function() { return (this.flags & 2097155) !== 0; }
- },
- isAppend: {
- get: function() { return (this.flags & 1024); }
- }
- });
- }
- if (stream.__proto__) {
- // reuse the object
- stream.__proto__ = FS.FSStream.prototype;
- } else {
- var newStream = new FS.FSStream();
- for (var p in stream) {
- newStream[p] = stream[p];
- }
- stream = newStream;
- }
- var fd = FS.nextfd(fd_start, fd_end);
- stream.fd = fd;
- FS.streams[fd] = stream;
- return stream;
- },closeStream:function (fd) {
- FS.streams[fd] = null;
- },getStreamFromPtr:function (ptr) {
- return FS.streams[ptr - 1];
- },getPtrForStream:function (stream) {
- return stream ? stream.fd + 1 : 0;
- },chrdev_stream_ops:{open:function (stream) {
- var device = FS.getDevice(stream.node.rdev);
- // override node's stream ops with the device's
- stream.stream_ops = device.stream_ops;
- // forward the open call
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- },llseek:function () {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }},major:function (dev) {
- return ((dev) >> 8);
- },minor:function (dev) {
- return ((dev) & 0xff);
- },makedev:function (ma, mi) {
- return ((ma) << 8 | (mi));
- },registerDevice:function (dev, ops) {
- FS.devices[dev] = { stream_ops: ops };
- },getDevice:function (dev) {
- return FS.devices[dev];
- },getMounts:function (mount) {
- var mounts = [];
- var check = [mount];
-
- while (check.length) {
- var m = check.pop();
-
- mounts.push(m);
-
- check.push.apply(check, m.mounts);
- }
-
- return mounts;
- },syncfs:function (populate, callback) {
- if (typeof(populate) === 'function') {
- callback = populate;
- populate = false;
- }
-
- var mounts = FS.getMounts(FS.root.mount);
- var completed = 0;
-
- function done(err) {
- if (err) {
- if (!done.errored) {
- done.errored = true;
- return callback(err);
- }
- return;
- }
- if (++completed >= mounts.length) {
- callback(null);
- }
- };
-
- // sync all mounts
- mounts.forEach(function (mount) {
- if (!mount.type.syncfs) {
- return done(null);
- }
- mount.type.syncfs(mount, populate, done);
- });
- },mount:function (type, opts, mountpoint) {
- var root = mountpoint === '/';
- var pseudo = !mountpoint;
- var node;
-
- if (root && FS.root) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- } else if (!root && !pseudo) {
- var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
-
- mountpoint = lookup.path; // use the absolute path
- node = lookup.node;
-
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
-
- if (!FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- }
-
- var mount = {
- type: type,
- opts: opts,
- mountpoint: mountpoint,
- mounts: []
- };
-
- // create a root node for the fs
- var mountRoot = type.mount(mount);
- mountRoot.mount = mount;
- mount.root = mountRoot;
-
- if (root) {
- FS.root = mountRoot;
- } else if (node) {
- // set as a mountpoint
- node.mounted = mount;
-
- // add the new mount to the current mount's children
- if (node.mount) {
- node.mount.mounts.push(mount);
- }
- }
-
- return mountRoot;
- },unmount:function (mountpoint) {
- var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
-
- if (!FS.isMountpoint(lookup.node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
-
- // destroy the nodes for this mount, and all its child mounts
- var node = lookup.node;
- var mount = node.mounted;
- var mounts = FS.getMounts(mount);
-
- Object.keys(FS.nameTable).forEach(function (hash) {
- var current = FS.nameTable[hash];
-
- while (current) {
- var next = current.name_next;
-
- if (mounts.indexOf(current.mount) !== -1) {
- FS.destroyNode(current);
- }
-
- current = next;
- }
- });
-
- // no longer a mountpoint
- node.mounted = null;
-
- // remove this mount from the child mounts
- var idx = node.mount.mounts.indexOf(mount);
- assert(idx !== -1);
- node.mount.mounts.splice(idx, 1);
- },lookup:function (parent, name) {
- return parent.node_ops.lookup(parent, name);
- },mknod:function (path, mode, dev) {
- var lookup = FS.lookupPath(path, { parent: true });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var err = FS.mayCreate(parent, name);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.mknod) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return parent.node_ops.mknod(parent, name, mode, dev);
- },create:function (path, mode) {
- mode = mode !== undefined ? mode : 438 /* 0666 */;
- mode &= 4095;
- mode |= 32768;
- return FS.mknod(path, mode, 0);
- },mkdir:function (path, mode) {
- mode = mode !== undefined ? mode : 511 /* 0777 */;
- mode &= 511 | 512;
- mode |= 16384;
- return FS.mknod(path, mode, 0);
- },mkdev:function (path, mode, dev) {
- if (typeof(dev) === 'undefined') {
- dev = mode;
- mode = 438 /* 0666 */;
- }
- mode |= 8192;
- return FS.mknod(path, mode, dev);
- },symlink:function (oldpath, newpath) {
- var lookup = FS.lookupPath(newpath, { parent: true });
- var parent = lookup.node;
- var newname = PATH.basename(newpath);
- var err = FS.mayCreate(parent, newname);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.symlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return parent.node_ops.symlink(parent, newname, oldpath);
- },rename:function (old_path, new_path) {
- var old_dirname = PATH.dirname(old_path);
- var new_dirname = PATH.dirname(new_path);
- var old_name = PATH.basename(old_path);
- var new_name = PATH.basename(new_path);
- // parents must exist
- var lookup, old_dir, new_dir;
- try {
- lookup = FS.lookupPath(old_path, { parent: true });
- old_dir = lookup.node;
- lookup = FS.lookupPath(new_path, { parent: true });
- new_dir = lookup.node;
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- // need to be part of the same mount
- if (old_dir.mount !== new_dir.mount) {
- throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
- }
- // source must exist
- var old_node = FS.lookupNode(old_dir, old_name);
- // old path should not be an ancestor of the new path
- var relative = PATH.relative(old_path, new_dirname);
- if (relative.charAt(0) !== '.') {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- // new path should not be an ancestor of the old path
- relative = PATH.relative(new_path, old_dirname);
- if (relative.charAt(0) !== '.') {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- // see if the new path already exists
- var new_node;
- try {
- new_node = FS.lookupNode(new_dir, new_name);
- } catch (e) {
- // not fatal
- }
- // early out if nothing needs to change
- if (old_node === new_node) {
- return;
- }
- // we'll need to delete the old entry
- var isdir = FS.isDir(old_node.mode);
- var err = FS.mayDelete(old_dir, old_name, isdir);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- // need delete permissions if we'll be overwriting.
- // need create permissions if new doesn't already exist.
- err = new_node ?
- FS.mayDelete(new_dir, new_name, isdir) :
- FS.mayCreate(new_dir, new_name);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!old_dir.node_ops.rename) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- // if we are going to change the parent, check write permissions
- if (new_dir !== old_dir) {
- err = FS.nodePermissions(old_dir, 'w');
- if (err) {
- throw new FS.ErrnoError(err);
- }
- }
- // remove the node from the lookup hash
- FS.hashRemoveNode(old_node);
- // do the underlying fs rename
- try {
- old_dir.node_ops.rename(old_node, new_dir, new_name);
- } catch (e) {
- throw e;
- } finally {
- // add the node back to the hash (in case node_ops.rename
- // changed its name)
- FS.hashAddNode(old_node);
- }
- },rmdir:function (path) {
- var lookup = FS.lookupPath(path, { parent: true });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var node = FS.lookupNode(parent, name);
- var err = FS.mayDelete(parent, name, true);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.rmdir) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- parent.node_ops.rmdir(parent, name);
- FS.destroyNode(node);
- },readdir:function (path) {
- var lookup = FS.lookupPath(path, { follow: true });
- var node = lookup.node;
- if (!node.node_ops.readdir) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- return node.node_ops.readdir(node);
- },unlink:function (path) {
- var lookup = FS.lookupPath(path, { parent: true });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var node = FS.lookupNode(parent, name);
- var err = FS.mayDelete(parent, name, false);
- if (err) {
- // POSIX says unlink should set EPERM, not EISDIR
- if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.unlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- parent.node_ops.unlink(parent, name);
- FS.destroyNode(node);
- },readlink:function (path) {
- var lookup = FS.lookupPath(path);
- var link = lookup.node;
- if (!link.node_ops.readlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return link.node_ops.readlink(link);
- },stat:function (path, dontFollow) {
- var lookup = FS.lookupPath(path, { follow: !dontFollow });
- var node = lookup.node;
- if (!node.node_ops.getattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return node.node_ops.getattr(node);
- },lstat:function (path) {
- return FS.stat(path, true);
- },chmod:function (path, mode, dontFollow) {
- var node;
- if (typeof path === 'string') {
- var lookup = FS.lookupPath(path, { follow: !dontFollow });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- node.node_ops.setattr(node, {
- mode: (mode & 4095) | (node.mode & ~4095),
- timestamp: Date.now()
- });
- },lchmod:function (path, mode) {
- FS.chmod(path, mode, true);
- },fchmod:function (fd, mode) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- FS.chmod(stream.node, mode);
- },chown:function (path, uid, gid, dontFollow) {
- var node;
- if (typeof path === 'string') {
- var lookup = FS.lookupPath(path, { follow: !dontFollow });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- node.node_ops.setattr(node, {
- timestamp: Date.now()
- // we ignore the uid / gid for now
- });
- },lchown:function (path, uid, gid) {
- FS.chown(path, uid, gid, true);
- },fchown:function (fd, uid, gid) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- FS.chown(stream.node, uid, gid);
- },truncate:function (path, len) {
- if (len < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var node;
- if (typeof path === 'string') {
- var lookup = FS.lookupPath(path, { follow: true });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!FS.isFile(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var err = FS.nodePermissions(node, 'w');
- if (err) {
- throw new FS.ErrnoError(err);
- }
- node.node_ops.setattr(node, {
- size: len,
- timestamp: Date.now()
- });
- },ftruncate:function (fd, len) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if ((stream.flags & 2097155) === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- FS.truncate(stream.node, len);
- },utime:function (path, atime, mtime) {
- var lookup = FS.lookupPath(path, { follow: true });
- var node = lookup.node;
- node.node_ops.setattr(node, {
- timestamp: Math.max(atime, mtime)
- });
- },open:function (path, flags, mode, fd_start, fd_end) {
- flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
- mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
- if ((flags & 64)) {
- mode = (mode & 4095) | 32768;
- } else {
- mode = 0;
- }
- var node;
- if (typeof path === 'object') {
- node = path;
- } else {
- path = PATH.normalize(path);
- try {
- var lookup = FS.lookupPath(path, {
- follow: !(flags & 131072)
- });
- node = lookup.node;
- } catch (e) {
- // ignore
- }
- }
- // perhaps we need to create the node
- if ((flags & 64)) {
- if (node) {
- // if O_CREAT and O_EXCL are set, error out if the node already exists
- if ((flags & 128)) {
- throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
- }
- } else {
- // node doesn't exist, try to create it
- node = FS.mknod(path, mode, 0);
- }
- }
- if (!node) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- // can't truncate a device
- if (FS.isChrdev(node.mode)) {
- flags &= ~512;
- }
- // check permissions
- var err = FS.mayOpen(node, flags);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- // do truncation if necessary
- if ((flags & 512)) {
- FS.truncate(node, 0);
- }
- // we've already handled these, don't pass down to the underlying vfs
- flags &= ~(128 | 512);
-
- // register the stream with the filesystem
- var stream = FS.createStream({
- node: node,
- path: FS.getPath(node), // we want the absolute path to the node
- flags: flags,
- seekable: true,
- position: 0,
- stream_ops: node.stream_ops,
- // used by the file family libc calls (fopen, fwrite, ferror, etc.)
- ungotten: [],
- error: false
- }, fd_start, fd_end);
- // call the new stream's open function
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- if (Module['logReadFiles'] && !(flags & 1)) {
- if (!FS.readFiles) FS.readFiles = {};
- if (!(path in FS.readFiles)) {
- FS.readFiles[path] = 1;
- Module['printErr']('read file: ' + path);
- }
- }
- return stream;
- },close:function (stream) {
- try {
- if (stream.stream_ops.close) {
- stream.stream_ops.close(stream);
- }
- } catch (e) {
- throw e;
- } finally {
- FS.closeStream(stream.fd);
- }
- },llseek:function (stream, offset, whence) {
- if (!stream.seekable || !stream.stream_ops.llseek) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- return stream.stream_ops.llseek(stream, offset, whence);
- },read:function (stream, buffer, offset, length, position) {
- if (length < 0 || position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & 2097155) === 1) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!stream.stream_ops.read) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var seeking = true;
- if (typeof position === 'undefined') {
- position = stream.position;
- seeking = false;
- } else if (!stream.seekable) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
- if (!seeking) stream.position += bytesRead;
- return bytesRead;
- },write:function (stream, buffer, offset, length, position, canOwn) {
- if (length < 0 || position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & 2097155) === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!stream.stream_ops.write) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var seeking = true;
- if (typeof position === 'undefined') {
- position = stream.position;
- seeking = false;
- } else if (!stream.seekable) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- if (stream.flags & 1024) {
- // seek to the end before writing in append mode
- FS.llseek(stream, 0, 2);
- }
- var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
- if (!seeking) stream.position += bytesWritten;
- return bytesWritten;
- },allocate:function (stream, offset, length) {
- if (offset < 0 || length <= 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & 2097155) === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- if (!stream.stream_ops.allocate) {
- throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
- }
- stream.stream_ops.allocate(stream, offset, length);
- },mmap:function (stream, buffer, offset, length, position, prot, flags) {
- // TODO if PROT is PROT_WRITE, make sure we have write access
- if ((stream.flags & 2097155) === 1) {
- throw new FS.ErrnoError(ERRNO_CODES.EACCES);
- }
- if (!stream.stream_ops.mmap) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
- },ioctl:function (stream, cmd, arg) {
- if (!stream.stream_ops.ioctl) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
- }
- return stream.stream_ops.ioctl(stream, cmd, arg);
- },readFile:function (path, opts) {
- opts = opts || {};
- opts.flags = opts.flags || 'r';
- opts.encoding = opts.encoding || 'binary';
- if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
- throw new Error('Invalid encoding type "' + opts.encoding + '"');
- }
- var ret;
- var stream = FS.open(path, opts.flags);
- var stat = FS.stat(path);
- var length = stat.size;
- var buf = new Uint8Array(length);
- FS.read(stream, buf, 0, length, 0);
- if (opts.encoding === 'utf8') {
- ret = '';
- var utf8 = new Runtime.UTF8Processor();
- for (var i = 0; i < length; i++) {
- ret += utf8.processCChar(buf[i]);
- }
- } else if (opts.encoding === 'binary') {
- ret = buf;
- }
- FS.close(stream);
- return ret;
- },writeFile:function (path, data, opts) {
- opts = opts || {};
- opts.flags = opts.flags || 'w';
- opts.encoding = opts.encoding || 'utf8';
- if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
- throw new Error('Invalid encoding type "' + opts.encoding + '"');
- }
- var stream = FS.open(path, opts.flags, opts.mode);
- if (opts.encoding === 'utf8') {
- var utf8 = new Runtime.UTF8Processor();
- var buf = new Uint8Array(utf8.processJSString(data));
- FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
- } else if (opts.encoding === 'binary') {
- FS.write(stream, data, 0, data.length, 0, opts.canOwn);
- }
- FS.close(stream);
- },cwd:function () {
- return FS.currentPath;
- },chdir:function (path) {
- var lookup = FS.lookupPath(path, { follow: true });
- if (!FS.isDir(lookup.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- var err = FS.nodePermissions(lookup.node, 'x');
- if (err) {
- throw new FS.ErrnoError(err);
- }
- FS.currentPath = lookup.path;
- },createDefaultDirectories:function () {
- FS.mkdir('/tmp');
- },createDefaultDevices:function () {
- // create /dev
- FS.mkdir('/dev');
- // setup /dev/null
- FS.registerDevice(FS.makedev(1, 3), {
- read: function() { return 0; },
- write: function() { return 0; }
- });
- FS.mkdev('/dev/null', FS.makedev(1, 3));
- // setup /dev/tty and /dev/tty1
- // stderr needs to print output using Module['printErr']
- // so we register a second tty just for it.
- TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
- TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
- FS.mkdev('/dev/tty', FS.makedev(5, 0));
- FS.mkdev('/dev/tty1', FS.makedev(6, 0));
- // we're not going to emulate the actual shm device,
- // just create the tmp dirs that reside in it commonly
- FS.mkdir('/dev/shm');
- FS.mkdir('/dev/shm/tmp');
- },createStandardStreams:function () {
- // TODO deprecate the old functionality of a single
- // input / output callback and that utilizes FS.createDevice
- // and instead require a unique set of stream ops
-
- // by default, we symlink the standard streams to the
- // default tty devices. however, if the standard streams
- // have been overwritten we create a unique device for
- // them instead.
- if (Module['stdin']) {
- FS.createDevice('/dev', 'stdin', Module['stdin']);
- } else {
- FS.symlink('/dev/tty', '/dev/stdin');
- }
- if (Module['stdout']) {
- FS.createDevice('/dev', 'stdout', null, Module['stdout']);
- } else {
- FS.symlink('/dev/tty', '/dev/stdout');
- }
- if (Module['stderr']) {
- FS.createDevice('/dev', 'stderr', null, Module['stderr']);
- } else {
- FS.symlink('/dev/tty1', '/dev/stderr');
- }
-
- // open default streams for the stdin, stdout and stderr devices
- var stdin = FS.open('/dev/stdin', 'r');
- HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
- assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
-
- var stdout = FS.open('/dev/stdout', 'w');
- HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
- assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
-
- var stderr = FS.open('/dev/stderr', 'w');
- HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
- assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
- },ensureErrnoError:function () {
- if (FS.ErrnoError) return;
- FS.ErrnoError = function ErrnoError(errno) {
- this.errno = errno;
- for (var key in ERRNO_CODES) {
- if (ERRNO_CODES[key] === errno) {
- this.code = key;
- break;
- }
- }
- this.message = ERRNO_MESSAGES[errno];
- };
- FS.ErrnoError.prototype = new Error();
- FS.ErrnoError.prototype.constructor = FS.ErrnoError;
- // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
- [ERRNO_CODES.ENOENT].forEach(function(code) {
- FS.genericErrors[code] = new FS.ErrnoError(code);
- FS.genericErrors[code].stack = '<generic error, no stack>';
- });
- },staticInit:function () {
- FS.ensureErrnoError();
-
- FS.nameTable = new Array(4096);
-
- FS.mount(MEMFS, {}, '/');
-
- FS.createDefaultDirectories();
- FS.createDefaultDevices();
- },init:function (input, output, error) {
- assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
- FS.init.initialized = true;
-
- FS.ensureErrnoError();
-
- // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
- Module['stdin'] = input || Module['stdin'];
- Module['stdout'] = output || Module['stdout'];
- Module['stderr'] = error || Module['stderr'];
-
- FS.createStandardStreams();
- },quit:function () {
- FS.init.initialized = false;
- for (var i = 0; i < FS.streams.length; i++) {
- var stream = FS.streams[i];
- if (!stream) {
- continue;
- }
- FS.close(stream);
- }
- },getMode:function (canRead, canWrite) {
- var mode = 0;
- if (canRead) mode |= 292 | 73;
- if (canWrite) mode |= 146;
- return mode;
- },joinPath:function (parts, forceRelative) {
- var path = PATH.join.apply(null, parts);
- if (forceRelative && path[0] == '/') path = path.substr(1);
- return path;
- },absolutePath:function (relative, base) {
- return PATH.resolve(base, relative);
- },standardizePath:function (path) {
- return PATH.normalize(path);
- },findObject:function (path, dontResolveLastLink) {
- var ret = FS.analyzePath(path, dontResolveLastLink);
- if (ret.exists) {
- return ret.object;
- } else {
- ___setErrNo(ret.error);
- return null;
- }
- },analyzePath:function (path, dontResolveLastLink) {
- // operate from within the context of the symlink's target
- try {
- var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
- path = lookup.path;
- } catch (e) {
- }
- var ret = {
- isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
- parentExists: false, parentPath: null, parentObject: null
- };
- try {
- var lookup = FS.lookupPath(path, { parent: true });
- ret.parentExists = true;
- ret.parentPath = lookup.path;
- ret.parentObject = lookup.node;
- ret.name = PATH.basename(path);
- lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
- ret.exists = true;
- ret.path = lookup.path;
- ret.object = lookup.node;
- ret.name = lookup.node.name;
- ret.isRoot = lookup.path === '/';
- } catch (e) {
- ret.error = e.errno;
- };
- return ret;
- },createFolder:function (parent, name, canRead, canWrite) {
- var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return FS.mkdir(path, mode);
- },createPath:function (parent, path, canRead, canWrite) {
- parent = typeof parent === 'string' ? parent : FS.getPath(parent);
- var parts = path.split('/').reverse();
- while (parts.length) {
- var part = parts.pop();
- if (!part) continue;
- var current = PATH.join2(parent, part);
- try {
- FS.mkdir(current);
- } catch (e) {
- // ignore EEXIST
- }
- parent = current;
- }
- return current;
- },createFile:function (parent, name, properties, canRead, canWrite) {
- var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return FS.create(path, mode);
- },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
- var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
- var mode = FS.getMode(canRead, canWrite);
- var node = FS.create(path, mode);
- if (data) {
- if (typeof data === 'string') {
- var arr = new Array(data.length);
- for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
- data = arr;
- }
- // make sure we can write to the file
- FS.chmod(node, mode | 146);
- var stream = FS.open(node, 'w');
- FS.write(stream, data, 0, data.length, 0, canOwn);
- FS.close(stream);
- FS.chmod(node, mode);
- }
- return node;
- },createDevice:function (parent, name, input, output) {
- var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(!!input, !!output);
- if (!FS.createDevice.major) FS.createDevice.major = 64;
- var dev = FS.makedev(FS.createDevice.major++, 0);
- // Create a fake device that a set of stream ops to emulate
- // the old behavior.
- FS.registerDevice(dev, {
- open: function(stream) {
- stream.seekable = false;
- },
- close: function(stream) {
- // flush any pending line data
- if (output && output.buffer && output.buffer.length) {
- output(10);
- }
- },
- read: function(stream, buffer, offset, length, pos /* ignored */) {
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = input();
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset+i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- },
- write: function(stream, buffer, offset, length, pos) {
- for (var i = 0; i < length; i++) {
- try {
- output(buffer[offset+i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- }
- });
- return FS.mkdev(path, mode, dev);
- },createLink:function (parent, name, target, canRead, canWrite) {
- var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- return FS.symlink(target, path);
- },forceLoadFile:function (obj) {
- if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
- var success = true;
- if (typeof XMLHttpRequest !== 'undefined') {
- throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
- } else if (Module['read']) {
- // Command-line.
- try {
- // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
- // read() will try to parse UTF8.
- obj.contents = intArrayFromString(Module['read'](obj.url), true);
- } catch (e) {
- success = false;
- }
- } else {
- throw new Error('Cannot load without read() or XMLHttpRequest.');
- }
- if (!success) ___setErrNo(ERRNO_CODES.EIO);
- return success;
- },createLazyFile:function (parent, name, url, canRead, canWrite) {
- if (typeof XMLHttpRequest !== 'undefined') {
- if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
- // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
- function LazyUint8Array() {
- this.lengthKnown = false;
- this.chunks = []; // Loaded chunks. Index is the chunk number
- }
- LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
- if (idx > this.length-1 || idx < 0) {
- return undefined;
- }
- var chunkOffset = idx % this.chunkSize;
- var chunkNum = Math.floor(idx / this.chunkSize);
- return this.getter(chunkNum)[chunkOffset];
- }
- LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
- this.getter = getter;
- }
- LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
- // Find length
- var xhr = new XMLHttpRequest();
- xhr.open('HEAD', url, false);
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- var datalength = Number(xhr.getResponseHeader("Content-length"));
- var header;
- var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
- var chunkSize = 1024*1024; // Chunk size in bytes
-
- if (!hasByteServing) chunkSize = datalength;
-
- // Function to get a range from the remote URL.
- var doXHR = (function(from, to) {
- if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
- if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
-
- // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, false);
- if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
-
- // Some hints to the browser that we want binary data.
- if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- }
-
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- if (xhr.response !== undefined) {
- return new Uint8Array(xhr.response || []);
- } else {
- return intArrayFromString(xhr.responseText || '', true);
- }
- });
- var lazyArray = this;
- lazyArray.setDataGetter(function(chunkNum) {
- var start = chunkNum * chunkSize;
- var end = (chunkNum+1) * chunkSize - 1; // including this byte
- end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
- lazyArray.chunks[chunkNum] = doXHR(start, end);
- }
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
- return lazyArray.chunks[chunkNum];
- });
-
- this._length = datalength;
- this._chunkSize = chunkSize;
- this.lengthKnown = true;
- }
-
- var lazyArray = new LazyUint8Array();
- Object.defineProperty(lazyArray, "length", {
- get: function() {
- if(!this.lengthKnown) {
- this.cacheLength();
- }
- return this._length;
- }
- });
- Object.defineProperty(lazyArray, "chunkSize", {
- get: function() {
- if(!this.lengthKnown) {
- this.cacheLength();
- }
- return this._chunkSize;
- }
- });
-
- var properties = { isDevice: false, contents: lazyArray };
- } else {
- var properties = { isDevice: false, url: url };
- }
-
- var node = FS.createFile(parent, name, properties, canRead, canWrite);
- // This is a total hack, but I want to get this lazy file code out of the
- // core of MEMFS. If we want to keep this lazy file concept I feel it should
- // be its own thin LAZYFS proxying calls to MEMFS.
- if (properties.contents) {
- node.contents = properties.contents;
- } else if (properties.url) {
- node.contents = null;
- node.url = properties.url;
- }
- // override each stream op with one that tries to force load the lazy file first
- var stream_ops = {};
- var keys = Object.keys(node.stream_ops);
- keys.forEach(function(key) {
- var fn = node.stream_ops[key];
- stream_ops[key] = function forceLoadLazyFile() {
- if (!FS.forceLoadFile(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- return fn.apply(null, arguments);
- };
- });
- // use a custom read function
- stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
- if (!FS.forceLoadFile(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- var contents = stream.node.contents;
- if (position >= contents.length)
- return 0;
- var size = Math.min(contents.length - position, length);
- assert(size >= 0);
- if (contents.slice) { // normal array
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents[position + i];
- }
- } else {
- for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
- buffer[offset + i] = contents.get(position + i);
- }
- }
- return size;
- };
- node.stream_ops = stream_ops;
- return node;
- },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
- Browser.init();
- // TODO we should allow people to just pass in a complete filename instead
- // of parent and name being that we just join them anyways
- var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
- function processData(byteArray) {
- function finish(byteArray) {
- if (!dontCreateFile) {
- FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
- }
- if (onload) onload();
- removeRunDependency('cp ' + fullname);
- }
- var handled = false;
- Module['preloadPlugins'].forEach(function(plugin) {
- if (handled) return;
- if (plugin['canHandle'](fullname)) {
- plugin['handle'](byteArray, fullname, finish, function() {
- if (onerror) onerror();
- removeRunDependency('cp ' + fullname);
- });
- handled = true;
- }
- });
- if (!handled) finish(byteArray);
- }
- addRunDependency('cp ' + fullname);
- if (typeof url == 'string') {
- Browser.asyncLoad(url, function(byteArray) {
- processData(byteArray);
- }, onerror);
- } else {
- processData(url);
- }
- },indexedDB:function () {
- return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
- },DB_NAME:function () {
- return 'EM_FS_' + window.location.pathname;
- },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
- onload = onload || function(){};
- onerror = onerror || function(){};
- var indexedDB = FS.indexedDB();
- try {
- var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
- } catch (e) {
- return onerror(e);
- }
- openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
- console.log('creating db');
- var db = openRequest.result;
- db.createObjectStore(FS.DB_STORE_NAME);
- };
- openRequest.onsuccess = function openRequest_onsuccess() {
- var db = openRequest.result;
- var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
- var files = transaction.objectStore(FS.DB_STORE_NAME);
- var ok = 0, fail = 0, total = paths.length;
- function finish() {
- if (fail == 0) onload(); else onerror();
- }
- paths.forEach(function(path) {
- var putRequest = files.put(FS.analyzePath(path).object.contents, path);
- putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
- putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
- });
- transaction.onerror = onerror;
- };
- openRequest.onerror = onerror;
- },loadFilesFromDB:function (paths, onload, onerror) {
- onload = onload || function(){};
- onerror = onerror || function(){};
- var indexedDB = FS.indexedDB();
- try {
- var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
- } catch (e) {
- return onerror(e);
- }
- openRequest.onupgradeneeded = onerror; // no database to load from
- openRequest.onsuccess = function openRequest_onsuccess() {
- var db = openRequest.result;
- try {
- var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
- } catch(e) {
- onerror(e);
- return;
- }
- var files = transaction.objectStore(FS.DB_STORE_NAME);
- var ok = 0, fail = 0, total = paths.length;
- function finish() {
- if (fail == 0) onload(); else onerror();
- }
- paths.forEach(function(path) {
- var getRequest = files.get(path);
- getRequest.onsuccess = function getRequest_onsuccess() {
- if (FS.analyzePath(path).exists) {
- FS.unlink(path);
- }
- FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
- ok++;
- if (ok + fail == total) finish();
- };
- getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
- });
- transaction.onerror = onerror;
- };
- openRequest.onerror = onerror;
- }};var PATH={splitPath:function (filename) {
- var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
- return splitPathRe.exec(filename).slice(1);
- },normalizeArray:function (parts, allowAboveRoot) {
- // if the path tries to go above the root, `up` ends up > 0
- var up = 0;
- for (var i = parts.length - 1; i >= 0; i--) {
- var last = parts[i];
- if (last === '.') {
- parts.splice(i, 1);
- } else if (last === '..') {
- parts.splice(i, 1);
- up++;
- } else if (up) {
- parts.splice(i, 1);
- up--;
- }
- }
- // if the path is allowed to go above the root, restore leading ..s
- if (allowAboveRoot) {
- for (; up--; up) {
- parts.unshift('..');
- }
- }
- return parts;
- },normalize:function (path) {
- var isAbsolute = path.charAt(0) === '/',
- trailingSlash = path.substr(-1) === '/';
- // Normalize the path
- path = PATH.normalizeArray(path.split('/').filter(function(p) {
- return !!p;
- }), !isAbsolute).join('/');
- if (!path && !isAbsolute) {
- path = '.';
- }
- if (path && trailingSlash) {
- path += '/';
- }
- return (isAbsolute ? '/' : '') + path;
- },dirname:function (path) {
- var result = PATH.splitPath(path),
- root = result[0],
- dir = result[1];
- if (!root && !dir) {
- // No dirname whatsoever
- return '.';
- }
- if (dir) {
- // It has a dirname, strip trailing slash
- dir = dir.substr(0, dir.length - 1);
- }
- return root + dir;
- },basename:function (path) {
- // EMSCRIPTEN return '/'' for '/', not an empty string
- if (path === '/') return '/';
- var lastSlash = path.lastIndexOf('/');
- if (lastSlash === -1) return path;
- return path.substr(lastSlash+1);
- },extname:function (path) {
- return PATH.splitPath(path)[3];
- },join:function () {
- var paths = Array.prototype.slice.call(arguments, 0);
- return PATH.normalize(paths.join('/'));
- },join2:function (l, r) {
- return PATH.normalize(l + '/' + r);
- },resolve:function () {
- var resolvedPath = '',
- resolvedAbsolute = false;
- for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
- var path = (i >= 0) ? arguments[i] : FS.cwd();
- // Skip empty and invalid entries
- if (typeof path !== 'string') {
- throw new TypeError('Arguments to path.resolve must be strings');
- } else if (!path) {
- continue;
- }
- resolvedPath = path + '/' + resolvedPath;
- resolvedAbsolute = path.charAt(0) === '/';
- }
- // At this point the path should be resolved to a full absolute path, but
- // handle relative paths to be safe (might happen when process.cwd() fails)
- resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
- return !!p;
- }), !resolvedAbsolute).join('/');
- return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
- },relative:function (from, to) {
- from = PATH.resolve(from).substr(1);
- to = PATH.resolve(to).substr(1);
- function trim(arr) {
- var start = 0;
- for (; start < arr.length; start++) {
- if (arr[start] !== '') break;
- }
- var end = arr.length - 1;
- for (; end >= 0; end--) {
- if (arr[end] !== '') break;
- }
- if (start > end) return [];
- return arr.slice(start, end - start + 1);
- }
- var fromParts = trim(from.split('/'));
- var toParts = trim(to.split('/'));
- var length = Math.min(fromParts.length, toParts.length);
- var samePartsLength = length;
- for (var i = 0; i < length; i++) {
- if (fromParts[i] !== toParts[i]) {
- samePartsLength = i;
- break;
- }
- }
- var outputParts = [];
- for (var i = samePartsLength; i < fromParts.length; i++) {
- outputParts.push('..');
- }
- outputParts = outputParts.concat(toParts.slice(samePartsLength));
- return outputParts.join('/');
- }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
- Browser.mainLoop.shouldPause = true;
- },resume:function () {
- if (Browser.mainLoop.paused) {
- Browser.mainLoop.paused = false;
- Browser.mainLoop.scheduler();
- }
- Browser.mainLoop.shouldPause = false;
- },updateStatus:function () {
- if (Module['setStatus']) {
- var message = Module['statusMessage'] || 'Please wait...';
- var remaining = Browser.mainLoop.remainingBlockers;
- var expected = Browser.mainLoop.expectedBlockers;
- if (remaining) {
- if (remaining < expected) {
- Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
- } else {
- Module['setStatus'](message);
- }
- } else {
- Module['setStatus']('');
- }
- }
- }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
- if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
-
- if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
- Browser.initted = true;
-
- try {
- new Blob();
- Browser.hasBlobConstructor = true;
- } catch(e) {
- Browser.hasBlobConstructor = false;
- console.log("warning: no blob constructor, cannot create blobs with mimetypes");
- }
- Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
- Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
- if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
- console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
- Module.noImageDecoding = true;
- }
-
- // Support for plugins that can process preloaded files. You can add more of these to
- // your app by creating and appending to Module.preloadPlugins.
- //
- // Each plugin is asked if it can handle a file based on the file's name. If it can,
- // it is given the file's raw data. When it is done, it calls a callback with the file's
- // (possibly modified) data. For example, a plugin might decompress a file, or it
- // might create some side data structure for use later (like an Image element, etc.).
-
- var imagePlugin = {};
- imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
- return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
- };
- imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
- var b = null;
- if (Browser.hasBlobConstructor) {
- try {
- b = new Blob([byteArray], { type: Browser.getMimetype(name) });
- if (b.size !== byteArray.length) { // Safari bug #118630
- // Safari's Blob can only take an ArrayBuffer
- b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
- }
- } catch(e) {
- Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
- }
- }
- if (!b) {
- var bb = new Browser.BlobBuilder();
- bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
- b = bb.getBlob();
- }
- var url = Browser.URLObject.createObjectURL(b);
- var img = new Image();
- img.onload = function img_onload() {
- assert(img.complete, 'Image ' + name + ' could not be decoded');
- var canvas = document.createElement('canvas');
- canvas.width = img.width;
- canvas.height = img.height;
- var ctx = canvas.getContext('2d');
- ctx.drawImage(img, 0, 0);
- Module["preloadedImages"][name] = canvas;
- Browser.URLObject.revokeObjectURL(url);
- if (onload) onload(byteArray);
- };
- img.onerror = function img_onerror(event) {
- console.log('Image ' + url + ' could not be decoded');
- if (onerror) onerror();
- };
- img.src = url;
- };
- Module['preloadPlugins'].push(imagePlugin);
-
- var audioPlugin = {};
- audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
- return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
- };
- audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
- var done = false;
- function finish(audio) {
- if (done) return;
- done = true;
- Module["preloadedAudios"][name] = audio;
- if (onload) onload(byteArray);
- }
- function fail() {
- if (done) return;
- done = true;
- Module["preloadedAudios"][name] = new Audio(); // empty shim
- if (onerror) onerror();
- }
- if (Browser.hasBlobConstructor) {
- try {
- var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
- } catch(e) {
- return fail();
- }
- var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
- var audio = new Audio();
- audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
- audio.onerror = function audio_onerror(event) {
- if (done) return;
- console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
- function encode64(data) {
- var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
- var PAD = '=';
- var ret = '';
- var leftchar = 0;
- var leftbits = 0;
- for (var i = 0; i < data.length; i++) {
- leftchar = (leftchar << 8) | data[i];
- leftbits += 8;
- while (leftbits >= 6) {
- var curr = (leftchar >> (leftbits-6)) & 0x3f;
- leftbits -= 6;
- ret += BASE[curr];
- }
- }
- if (leftbits == 2) {
- ret += BASE[(leftchar&3) << 4];
- ret += PAD + PAD;
- } else if (leftbits == 4) {
- ret += BASE[(leftchar&0xf) << 2];
- ret += PAD;
- }
- return ret;
- }
- audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
- finish(audio); // we don't wait for confirmation this worked - but it's worth trying
- };
- audio.src = url;
- // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
- Browser.safeSetTimeout(function() {
- finish(audio); // try to use it even though it is not necessarily ready to play
- }, 10000);
- } else {
- return fail();
- }
- };
- Module['preloadPlugins'].push(audioPlugin);
-
- // Canvas event setup
-
- var canvas = Module['canvas'];
-
- // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
- // Module['forcedAspectRatio'] = 4 / 3;
-
- canvas.requestPointerLock = canvas['requestPointerLock'] ||
- canvas['mozRequestPointerLock'] ||
- canvas['webkitRequestPointerLock'] ||
- canvas['msRequestPointerLock'] ||
- function(){};
- canvas.exitPointerLock = document['exitPointerLock'] ||
- document['mozExitPointerLock'] ||
- document['webkitExitPointerLock'] ||
- document['msExitPointerLock'] ||
- function(){}; // no-op if function does not exist
- canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
-
- function pointerLockChange() {
- Browser.pointerLock = document['pointerLockElement'] === canvas ||
- document['mozPointerLockElement'] === canvas ||
- document['webkitPointerLockElement'] === canvas ||
- document['msPointerLockElement'] === canvas;
- }
-
- document.addEventListener('pointerlockchange', pointerLockChange, false);
- document.addEventListener('mozpointerlockchange', pointerLockChange, false);
- document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
- document.addEventListener('mspointerlockchange', pointerLockChange, false);
-
- if (Module['elementPointerLock']) {
- canvas.addEventListener("click", function(ev) {
- if (!Browser.pointerLock && canvas.requestPointerLock) {
- canvas.requestPointerLock();
- ev.preventDefault();
- }
- }, false);
- }
- },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
- var ctx;
- var errorInfo = '?';
- function onContextCreationError(event) {
- errorInfo = event.statusMessage || errorInfo;
- }
- try {
- if (useWebGL) {
- var contextAttributes = {
- antialias: false,
- alpha: false
- };
-
- if (webGLContextAttributes) {
- for (var attribute in webGLContextAttributes) {
- contextAttributes[attribute] = webGLContextAttributes[attribute];
- }
- }
-
-
- canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
- try {
- ['experimental-webgl', 'webgl'].some(function(webglId) {
- return ctx = canvas.getContext(webglId, contextAttributes);
- });
- } finally {
- canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
- }
- } else {
- ctx = canvas.getContext('2d');
- }
- if (!ctx) throw ':(';
- } catch (e) {
- Module.print('Could not create canvas: ' + [errorInfo, e]);
- return null;
- }
- if (useWebGL) {
- // Set the background of the WebGL canvas to black
- canvas.style.backgroundColor = "black";
-
- // Warn on context loss
- canvas.addEventListener('webglcontextlost', function(event) {
- alert('WebGL context lost. You will need to reload the page.');
- }, false);
- }
- if (setInModule) {
- GLctx = Module.ctx = ctx;
- Module.useWebGL = useWebGL;
- Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
- Browser.init();
- }
- return ctx;
- },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
- Browser.lockPointer = lockPointer;
- Browser.resizeCanvas = resizeCanvas;
- if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
- if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
-
- var canvas = Module['canvas'];
- var canvasContainer = canvas.parentNode;
- function fullScreenChange() {
- Browser.isFullScreen = false;
- if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
- document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
- document['fullScreenElement'] || document['fullscreenElement'] ||
- document['msFullScreenElement'] || document['msFullscreenElement'] ||
- document['webkitCurrentFullScreenElement']) === canvasContainer) {
- canvas.cancelFullScreen = document['cancelFullScreen'] ||
- document['mozCancelFullScreen'] ||
- document['webkitCancelFullScreen'] ||
- document['msExitFullscreen'] ||
- document['exitFullscreen'] ||
- function() {};
- canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
- if (Browser.lockPointer) canvas.requestPointerLock();
- Browser.isFullScreen = true;
- if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
- } else {
-
- // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
- var canvasContainer = canvas.parentNode;
- canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
- canvasContainer.parentNode.removeChild(canvasContainer);
-
- if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
- }
- if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
- Browser.updateCanvasDimensions(canvas);
- }
-
- if (!Browser.fullScreenHandlersInstalled) {
- Browser.fullScreenHandlersInstalled = true;
- document.addEventListener('fullscreenchange', fullScreenChange, false);
- document.addEventListener('mozfullscreenchange', fullScreenChange, false);
- document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
- document.addEventListener('MSFullscreenChange', fullScreenChange, false);
- }
-
- // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
- var canvasContainer = document.createElement("div");
- canvas.parentNode.insertBefore(canvasContainer, canvas);
- canvasContainer.appendChild(canvas);
-
- // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
- canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
- canvasContainer['mozRequestFullScreen'] ||
- canvasContainer['msRequestFullscreen'] ||
- (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
- canvasContainer.requestFullScreen();
- },requestAnimationFrame:function requestAnimationFrame(func) {
- if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
- setTimeout(func, 1000/60);
- } else {
- if (!window.requestAnimationFrame) {
- window.requestAnimationFrame = window['requestAnimationFrame'] ||
- window['mozRequestAnimationFrame'] ||
- window['webkitRequestAnimationFrame'] ||
- window['msRequestAnimationFrame'] ||
- window['oRequestAnimationFrame'] ||
- window['setTimeout'];
- }
- window.requestAnimationFrame(func);
- }
- },safeCallback:function (func) {
- return function() {
- if (!ABORT) return func.apply(null, arguments);
- };
- },safeRequestAnimationFrame:function (func) {
- return Browser.requestAnimationFrame(function() {
- if (!ABORT) func();
- });
- },safeSetTimeout:function (func, timeout) {
- return setTimeout(function() {
- if (!ABORT) func();
- }, timeout);
- },safeSetInterval:function (func, timeout) {
- return setInterval(function() {
- if (!ABORT) func();
- }, timeout);
- },getMimetype:function (name) {
- return {
- 'jpg': 'image/jpeg',
- 'jpeg': 'image/jpeg',
- 'png': 'image/png',
- 'bmp': 'image/bmp',
- 'ogg': 'audio/ogg',
- 'wav': 'audio/wav',
- 'mp3': 'audio/mpeg'
- }[name.substr(name.lastIndexOf('.')+1)];
- },getUserMedia:function (func) {
- if(!window.getUserMedia) {
- window.getUserMedia = navigator['getUserMedia'] ||
- navigator['mozGetUserMedia'];
- }
- window.getUserMedia(func);
- },getMovementX:function (event) {
- return event['movementX'] ||
- event['mozMovementX'] ||
- event['webkitMovementX'] ||
- 0;
- },getMovementY:function (event) {
- return event['movementY'] ||
- event['mozMovementY'] ||
- event['webkitMovementY'] ||
- 0;
- },getMouseWheelDelta:function (event) {
- return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
- },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
- if (Browser.pointerLock) {
- // When the pointer is locked, calculate the coordinates
- // based on the movement of the mouse.
- // Workaround for Firefox bug 764498
- if (event.type != 'mousemove' &&
- ('mozMovementX' in event)) {
- Browser.mouseMovementX = Browser.mouseMovementY = 0;
- } else {
- Browser.mouseMovementX = Browser.getMovementX(event);
- Browser.mouseMovementY = Browser.getMovementY(event);
- }
-
- // check if SDL is available
- if (typeof SDL != "undefined") {
- Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
- Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
- } else {
- // just add the mouse delta to the current absolut mouse position
- // FIXME: ideally this should be clamped against the canvas size and zero
- Browser.mouseX += Browser.mouseMovementX;
- Browser.mouseY += Browser.mouseMovementY;
- }
- } else {
- // Otherwise, calculate the movement based on the changes
- // in the coordinates.
- var rect = Module["canvas"].getBoundingClientRect();
- var x, y;
-
- // Neither .scrollX or .pageXOffset are defined in a spec, but
- // we prefer .scrollX because it is currently in a spec draft.
- // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
- var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
- var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
- if (event.type == 'touchstart' ||
- event.type == 'touchend' ||
- event.type == 'touchmove') {
- var t = event.touches.item(0);
- if (t) {
- x = t.pageX - (scrollX + rect.left);
- y = t.pageY - (scrollY + rect.top);
- } else {
- return;
- }
- } else {
- x = event.pageX - (scrollX + rect.left);
- y = event.pageY - (scrollY + rect.top);
- }
-
- // the canvas might be CSS-scaled compared to its backbuffer;
- // SDL-using content will want mouse coordinates in terms
- // of backbuffer units.
- var cw = Module["canvas"].width;
- var ch = Module["canvas"].height;
- x = x * (cw / rect.width);
- y = y * (ch / rect.height);
-
- Browser.mouseMovementX = x - Browser.mouseX;
- Browser.mouseMovementY = y - Browser.mouseY;
- Browser.mouseX = x;
- Browser.mouseY = y;
- }
- },xhrLoad:function (url, onload, onerror) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.onload = function xhr_onload() {
- if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
- onload(xhr.response);
- } else {
- onerror();
- }
- };
- xhr.onerror = onerror;
- xhr.send(null);
- },asyncLoad:function (url, onload, onerror, noRunDep) {
- Browser.xhrLoad(url, function(arrayBuffer) {
- assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
- onload(new Uint8Array(arrayBuffer));
- if (!noRunDep) removeRunDependency('al ' + url);
- }, function(event) {
- if (onerror) {
- onerror();
- } else {
- throw 'Loading data file "' + url + '" failed.';
- }
- });
- if (!noRunDep) addRunDependency('al ' + url);
- },resizeListeners:[],updateResizeListeners:function () {
- var canvas = Module['canvas'];
- Browser.resizeListeners.forEach(function(listener) {
- listener(canvas.width, canvas.height);
- });
- },setCanvasSize:function (width, height, noUpdates) {
- var canvas = Module['canvas'];
- Browser.updateCanvasDimensions(canvas, width, height);
- if (!noUpdates) Browser.updateResizeListeners();
- },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
- // check if SDL is available
- if (typeof SDL != "undefined") {
- var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
- flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
- HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
- }
- Browser.updateResizeListeners();
- },setWindowedCanvasSize:function () {
- // check if SDL is available
- if (typeof SDL != "undefined") {
- var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
- flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
- HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
- }
- Browser.updateResizeListeners();
- },updateCanvasDimensions:function (canvas, wNative, hNative) {
- if (wNative && hNative) {
- canvas.widthNative = wNative;
- canvas.heightNative = hNative;
- } else {
- wNative = canvas.widthNative;
- hNative = canvas.heightNative;
- }
- var w = wNative;
- var h = hNative;
- if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
- if (w/h < Module['forcedAspectRatio']) {
- w = Math.round(h * Module['forcedAspectRatio']);
- } else {
- h = Math.round(w / Module['forcedAspectRatio']);
- }
- }
- if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
- document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
- document['fullScreenElement'] || document['fullscreenElement'] ||
- document['msFullScreenElement'] || document['msFullscreenElement'] ||
- document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
- var factor = Math.min(screen.width / w, screen.height / h);
- w = Math.round(w * factor);
- h = Math.round(h * factor);
- }
- if (Browser.resizeCanvas) {
- if (canvas.width != w) canvas.width = w;
- if (canvas.height != h) canvas.height = h;
- if (typeof canvas.style != 'undefined') {
- canvas.style.removeProperty( "width");
- canvas.style.removeProperty("height");
- }
- } else {
- if (canvas.width != wNative) canvas.width = wNative;
- if (canvas.height != hNative) canvas.height = hNative;
- if (typeof canvas.style != 'undefined') {
- if (w != wNative || h != hNative) {
- canvas.style.setProperty( "width", w + "px", "important");
- canvas.style.setProperty("height", h + "px", "important");
- } else {
- canvas.style.removeProperty( "width");
- canvas.style.removeProperty("height");
- }
- }
- }
- }};
-
-
- Module["_memset"] = _memset;
-
-
- Module["_strlen"] = _strlen;
-
-
- function _emscripten_memcpy_big(dest, src, num) {
- HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
- return dest;
- }
- Module["_memcpy"] = _memcpy;
-
- function _free() {
- }
- Module["_free"] = _free;
-Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
- Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
- Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
- Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
- Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
- Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
-FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
-___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
-__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
-if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
-STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
-
-staticSealed = true; // seal the static portion of memory
-
-STACK_MAX = STACK_BASE + 5242880;
-
-DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
-
-assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
-
-
-var Math_min = Math.min;
-function asmPrintInt(x, y) {
- Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
-}
-function asmPrintFloat(x, y) {
- Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
-}
-// EMSCRIPTEN_START_ASM
-var asm=(function(global,env,buffer){"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.tempDoublePtr|0;var l=env.ABORT|0;var m=0;var n=0;var o=0;var p=0;var q=+env.NaN,r=+env.Infinity;var s=0,t=0,u=0,v=0,w=0.0,x=0,y=0,z=0,A=0.0;var B=0;var C=0;var D=0;var E=0;var F=0;var G=0;var H=0;var I=0;var J=0;var K=0;var L=global.Math.floor;var M=global.Math.abs;var N=global.Math.sqrt;var O=global.Math.pow;var P=global.Math.cos;var Q=global.Math.sin;var R=global.Math.tan;var S=global.Math.acos;var T=global.Math.asin;var U=global.Math.atan;var V=global.Math.atan2;var W=global.Math.exp;var X=global.Math.log;var Y=global.Math.ceil;var Z=global.Math.imul;var _=env.abort;var $=env.assert;var aa=env.asmPrintInt;var ba=env.asmPrintFloat;var ca=env.min;var da=env._malloc;var ea=env._fflush;var fa=env._free;var ga=env._emscripten_memcpy_big;var ha=env.___setErrNo;var ia=0.0;
-// EMSCRIPTEN_START_FUNCS
-function ja(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+7&-8;return b|0}function ka(){return i|0}function la(a){a=a|0;i=a}function ma(a,b){a=a|0;b=b|0;if((m|0)==0){m=a;n=b}}function na(b){b=b|0;a[k]=a[b];a[k+1|0]=a[b+1|0];a[k+2|0]=a[b+2|0];a[k+3|0]=a[b+3|0]}function oa(b){b=b|0;a[k]=a[b];a[k+1|0]=a[b+1|0];a[k+2|0]=a[b+2|0];a[k+3|0]=a[b+3|0];a[k+4|0]=a[b+4|0];a[k+5|0]=a[b+5|0];a[k+6|0]=a[b+6|0];a[k+7|0]=a[b+7|0]}function pa(a){a=a|0;B=a}function qa(a){a=a|0;C=a}function ra(a){a=a|0;D=a}function sa(a){a=a|0;E=a}function ta(a){a=a|0;F=a}function ua(a){a=a|0;G=a}function va(a){a=a|0;H=a}function wa(a){a=a|0;I=a}function xa(a){a=a|0;J=a}function ya(a){a=a|0;K=a}function za(a){a=a|0;var b=0,d=0,e=0,f=0,h=0,j=0.0;a=i;c[2]=74755;b=74755;d=1;while(1){e=b;f=1;do{e=(e*1309|0)+13849&65535;g[16+(d*164|0)+(f<<2)>>2]=+(((e>>>0)%120|0)+ -60|0)/3.0;f=f+1|0;}while((f|0)!=41);f=d+1|0;if((f|0)==41){break}else{b=e;d=f}}c[2]=e;d=e;e=1;while(1){h=d;b=1;do{h=(h*1309|0)+13849&65535;g[6744+(e*164|0)+(b<<2)>>2]=+(((h>>>0)%120|0)+ -60|0)/3.0;b=b+1|0;}while((b|0)!=41);b=e+1|0;if((b|0)==41){break}else{d=h;e=b}}c[2]=h;h=1;do{e=1;do{d=13472+(h*164|0)+(e<<2)|0;g[d>>2]=0.0;j=0.0;b=1;do{j=j+ +g[16+(h*164|0)+(b<<2)>>2]*+g[6744+(b*164|0)+(e<<2)>>2];b=b+1|0;}while((b|0)!=41);g[d>>2]=j;e=e+1|0;}while((e|0)!=41);h=h+1|0;}while((h|0)!=41);i=a;return}function Aa(){var a=0,b=0;a=i;b=0;do{za(0);b=b+1|0;}while((b|0)!=5e3);i=a;return 0}function Ba(){}function Ca(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;g=b&3;h=d|d<<8|d<<16|d<<24;i=f&~3;if(g){g=b+4-g|0;while((b|0)<(g|0)){a[b]=d;b=b+1|0}}while((b|0)<(i|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b]=d;b=b+1|0}return b-e|0}function Da(b){b=b|0;var c=0;c=b;while(a[c]|0){c=c+1|0}return c-b|0}function Ea(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return ga(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if((e|0)==0)return f|0;a[b]=a[d]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b]=a[d]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}
-
-
-
-
-// EMSCRIPTEN_END_FUNCS
-return{_strlen:Da,_memcpy:Ea,_main:Aa,_memset:Ca,runPostSets:Ba,stackAlloc:ja,stackSave:ka,stackRestore:la,setThrew:ma,setTempRet0:pa,setTempRet1:qa,setTempRet2:ra,setTempRet3:sa,setTempRet4:ta,setTempRet5:ua,setTempRet6:va,setTempRet7:wa,setTempRet8:xa,setTempRet9:ya}})
-
-
-// EMSCRIPTEN_END_ASM
-({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_malloc": _malloc, "_fflush": _fflush, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "___setErrNo": ___setErrNo, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
-var _strlen = Module["_strlen"] = asm["_strlen"];
-var _memcpy = Module["_memcpy"] = asm["_memcpy"];
-var _main = Module["_main"] = asm["_main"];
-var _memset = Module["_memset"] = asm["_memset"];
-var runPostSets = Module["runPostSets"] = asm["runPostSets"];
-
-Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
-Runtime.stackSave = function() { return asm['stackSave']() };
-Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
-
-
-// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
-var i64Math = null;
-
-// === Auto-generated postamble setup entry stuff ===
-
-if (memoryInitializer) {
- if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
- var data = Module['readBinary'](memoryInitializer);
- HEAPU8.set(data, STATIC_BASE);
- } else {
- addRunDependency('memory initializer');
- Browser.asyncLoad(memoryInitializer, function(data) {
- HEAPU8.set(data, STATIC_BASE);
- removeRunDependency('memory initializer');
- }, function(data) {
- throw 'could not load memory initializer ' + memoryInitializer;
- });
- }
-}
-
-function ExitStatus(status) {
- this.name = "ExitStatus";
- this.message = "Program terminated with exit(" + status + ")";
- this.status = status;
-};
-ExitStatus.prototype = new Error();
-ExitStatus.prototype.constructor = ExitStatus;
-
-var initialStackTop;
-var preloadStartTime = null;
-var calledMain = false;
-
-dependenciesFulfilled = function runCaller() {
- // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
- if (!Module['calledRun'] && shouldRunNow) run();
- if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
-}
-
-Module['callMain'] = Module.callMain = function callMain(args) {
- assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
- assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
-
- args = args || [];
-
- if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
- Module.printErr('preload time: ' + (Date.now() - preloadStartTime) + ' ms');
- }
-
- ensureInitRuntime();
-
- var argc = args.length+1;
- function pad() {
- for (var i = 0; i < 4-1; i++) {
- argv.push(0);
- }
- }
- var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
- pad();
- for (var i = 0; i < argc-1; i = i + 1) {
- argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
- pad();
- }
- argv.push(0);
- argv = allocate(argv, 'i32', ALLOC_NORMAL);
-
- initialStackTop = STACKTOP;
-
- try {
-
- var ret = Module['_main'](argc, argv, 0);
-
-
- // if we're not running an evented main loop, it's time to exit
- if (!Module['noExitRuntime']) {
- exit(ret);
- }
- }
- catch(e) {
- if (e instanceof ExitStatus) {
- // exit() throws this once it's done to make sure execution
- // has been stopped completely
- return;
- } else if (e == 'SimulateInfiniteLoop') {
- // running an evented main loop, don't immediately exit
- Module['noExitRuntime'] = true;
- return;
- } else {
- if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
- throw e;
- }
- } finally {
- calledMain = true;
- }
-}
-
-
-
-
-function run(args) {
- args = args || Module['arguments'];
-
- if (preloadStartTime === null) preloadStartTime = Date.now();
-
- if (runDependencies > 0) {
- Module.printErr('run() called, but dependencies remain, so not running');
- return;
- }
-
- preRun();
-
- if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
- if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
-
- function doRun() {
- if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
- Module['calledRun'] = true;
-
- ensureInitRuntime();
-
- preMain();
-
- if (Module['_main'] && shouldRunNow) {
- Module['callMain'](args);
- }
-
- postRun();
- }
-
- if (Module['setStatus']) {
- Module['setStatus']('Running...');
- setTimeout(function() {
- setTimeout(function() {
- Module['setStatus']('');
- }, 1);
- if (!ABORT) doRun();
- }, 1);
- } else {
- doRun();
- }
-}
-Module['run'] = Module.run = run;
-
-function exit(status) {
- ABORT = true;
- EXITSTATUS = status;
- STACKTOP = initialStackTop;
-
- // exit the runtime
- exitRuntime();
-
- // TODO We should handle this differently based on environment.
- // In the browser, the best we can do is throw an exception
- // to halt execution, but in node we could process.exit and
- // I'd imagine SM shell would have something equivalent.
- // This would let us set a proper exit status (which
- // would be great for checking test exit statuses).
- // https://github.com/kripken/emscripten/issues/1371
-
- // throw an exception to halt the current execution
- throw new ExitStatus(status);
-}
-Module['exit'] = Module.exit = exit;
-
-function abort(text) {
- if (text) {
- Module.print(text);
- Module.printErr(text);
- }
-
- ABORT = true;
- EXITSTATUS = 1;
-
- var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
-
- throw 'abort() at ' + stackTrace() + extra;
-}
-Module['abort'] = Module.abort = abort;
-
-// {{PRE_RUN_ADDITIONS}}
-
-if (Module['preInit']) {
- if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
- while (Module['preInit'].length > 0) {
- Module['preInit'].pop()();
- }
-}
-
-// shouldRunNow refers to calling main(), not run().
-var shouldRunNow = true;
-if (Module['noInitialRun']) {
- shouldRunNow = false;
-}
-
-run();
-
-}
-
-let console = {
- log() { }
-}
-
-class Benchmark {
- runIteration() {
- run();
- }
-}
diff --git a/sqlite3/.gitignore b/sqlite3/.gitignore
new file mode 100644
index 0000000..0f55b11
--- /dev/null
+++ b/sqlite3/.gitignore
@@ -0,0 +1,2 @@
+/sqlite-src-*/
+/sqlite-src-*.zip
diff --git a/sqlite3/README.md b/sqlite3/README.md
new file mode 100644
index 0000000..f84125d
--- /dev/null
+++ b/sqlite3/README.md
@@ -0,0 +1,51 @@
+# Official sqlite3 benchmark, compiled to WebAssembly
+
+This is a Wasm (shell-only) build of SQLite's official `speedtest1.c` benchmark program.
+Quoting from https://sqlite.org/cpu.html:
+> This program strives to exercise the SQLite library in a way that is typical of real-world applications. Of course, every application is different, and so no test program can exactly mirror the behavior of all applications. The speedtest1.c program is updated from time to time as the SQLite developers' understanding of what constitutes "typical" usage evolves.
+
+## Build Instructions
+
+See `build.sh` or just run it.
+See `build.log` for the last build time, used sources, and toolchain versions.
+
+Prerequisites:
+- Emscripten: https://emscripten.org. Make sure `emcc` is on your `PATH`, e.g., by running `source /path/to/emsdk_env.sh`.
+- `wasm-strip`: Install WABT, e.g., via `sudo apt install wabt` or by compiling yourself from the source at https://github.com/WebAssembly/wabt.
+
+Since this benchmark is meant for the developers of SQLite, it is not part of the official Wasm build of SQLite at https://sqlite.org/wasm/doc/trunk/index.md and also not contained in the "amalgamation" single-file source code of SQLite (see https://sqlite.org/amalgamation.html).
+So we need to build it ourselves from the full sources.
+You can download the full SQLite source tree from https://sqlite.org/download.html.
+See under "Alternative Source Code Formats" or search for "Snapshot of the complete (raw) source tree for SQLite".
+
+## Running in JS shells
+
+The SQLite developers only maintain compatibility of the Wasm build for running inside browsers, so `benchmark.js` contains some polyfills to run it JavaScript shells (such as `d8` (V8), `js` (SpiderMonkey), and `jsc` (JavaScriptCore)).
+Ideally, it should run just via `$shell benchmark.js` from the current directory.
+
+To keep the shell runner and browser results consistent, the benchmark is configured to never use OPFS (Origin Private File System) as the underlying storage layer ("VFS" in SQLite), since that is not available in shells.
+It might thus show slightly different performance characteristics compared to the upstream `speedtest1.html` running with OPFS.
+
+## Running the upstream version of the benchmark in browsers
+
+Start a webserver in `build/` that serves with the correct headers (CORS/COOP/COEP) set for Wasm execution.
+E.g., this simple Python server will do:
+```
+#!/usr/bin/env python3
+from http.server import HTTPServer, SimpleHTTPRequestHandler, test
+import sys
+
+class CORSRequestHandler (SimpleHTTPRequestHandler):
+ def end_headers (self):
+ self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
+ self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
+
+ SimpleHTTPRequestHandler.end_headers(self)
+
+if __name__ == '__main__':
+ test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8083)
+```
+
+Then browse to http://localhost:8083/speedtest1.html.
+(Note that, e.g., Chrome requires `localhost`, not an IP!)
+Because the computation happens on the main thread, it may hang for a little while but should show the console output afterwards.
diff --git a/sqlite3/benchmark.js b/sqlite3/benchmark.js
new file mode 100644
index 0000000..1ac0a45
--- /dev/null
+++ b/sqlite3/benchmark.js
@@ -0,0 +1,73 @@
+// Copyright 2024 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const inJetStreamRunner = typeof globalThis.benchmarkTime !== "undefined";
+if (!inJetStreamRunner) {
+ load("polyfills.js");
+
+ // Exports `sqlite3InitModule()` and contains the main code.
+ load("build/jswasm/speedtest1.js");
+
+ // Load Wasm binary from disk.
+ globalThis.Module = {
+ wasmBinary: read("build/jswasm/speedtest1.wasm", "binary"),
+ };
+}
+
+// Make sure we never initialize OPFS by removing one of it's APIs (see
+// `installOpfsVfs` in the generated JavaScript code of sqlite).
+// We never want to use it anyway (see VFS config below) and this way we don't
+// waste cycles on the browser runner to initialize it.
+delete globalThis.FileSystemHandle;
+
+// Simplified from inline JavaScript in `speedtest1.html`.
+function runTests(sqlite3Module) {
+ // Configure the VFS to use.
+ // Don't use OPFS, WASMFS (which is on top of OPFS), or kvvfs, since they all
+ // use persistent browser storage (localStorage or OPFS), which is not
+ // available in JavaScript shells.
+ // Also don't use memfs, since that crashes with a NULL function pointer.
+ // Instead, make the default VFS explicit.
+ const capi = sqlite3Module.capi
+ console.log("Available SQLite VFS:", capi.sqlite3_js_vfs_list());
+ const vfs = "unix";
+ console.log("Using VFS:", vfs);
+ const pVfs = capi.sqlite3_vfs_find(vfs);
+ if (!pVfs) {
+ console.error("Error: Unknown VFS:", vfs);
+ return;
+ }
+
+ // These arguments should match the upstream browser runner `speedtest1.html`.
+ let argv = [
+ "speedtest1",
+ "--singlethread",
+ //"--nomutex",
+ //"--nosync",
+ //"--memdb", // note that memdb trumps the filename arg
+ "--nomemstat",
+ "--big-transactions" /*important for tests 410 and 510!*/,
+ "--size", "20", // To speedup, default is 100 (and takes about 4s).
+ "--vfs", vfs, // See VFS comment above.
+ ];
+
+ console.log("Calling main with argv:", argv);
+ const wasm = sqlite3Module.wasm;
+ wasm.scopedAllocPush(); // Required for `scopedAllocMainArgv()`.
+ wasm.xCall("wasm_main", argv.length, wasm.scopedAllocMainArgv(argv));
+ wasm.scopedAllocPop();
+}
+
+async function doRun() {
+ let start = benchmarkTime();
+ const sqliteModule = await sqlite3InitModule(Module);
+ reportCompileTime(benchmarkTime() - start);
+
+ start = benchmarkTime();
+ runTests(sqliteModule);
+ reportRunTime(benchmarkTime() - start);
+}
+if (!inJetStreamRunner) {
+ sqlite3InitModule(Module).then(runTests);
+}
diff --git a/sqlite3/build.log b/sqlite3/build.log
new file mode 100644
index 0000000..8c57c22
--- /dev/null
+++ b/sqlite3/build.log
@@ -0,0 +1,11 @@
+Built on 2024-12-05 14:24:19+01:00
+
+Toolchain versions
+emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.71 (4171ae200b77a6c266b0e1ebb507d61d1ade3501)
+wasm-strip 1.0.34
+
+Getting sources from https://sqlite.org/2024/sqlite-src-3470100.zip
+
+Building...
+Copying files from sqlite-src-*/ext/wasm/ into build/
+Build success
diff --git a/sqlite3/build.sh b/sqlite3/build.sh
new file mode 100755
index 0000000..ff7b067
--- /dev/null
+++ b/sqlite3/build.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+set -e
+set -o pipefail
+
+# Cleanup old files.
+rm sqlite-src-*.zip
+rm -rf sqlite-src-*/
+rm -rf build/
+
+touch build.log
+BUILD_LOG="$(realpath build.log)"
+echo -e "Built on $(date -u '+%Y-%m-%dT%H:%M:%SZ')\n" | tee "$BUILD_LOG"
+
+echo "Toolchain versions" | tee -a "$BUILD_LOG"
+emcc --version | head -n1 | tee -a "$BUILD_LOG"
+echo -e "wasm-strip $(wasm-strip --version)\n" | tee -a "$BUILD_LOG"
+
+# Check https://sqlite.org/download.html and update the source link, if needed.
+SQLITE_SRC_URL="https://sqlite.org/2024/sqlite-src-3470100.zip"
+echo -e "Getting sources from $SQLITE_SRC_URL\n" | tee -a "$BUILD_LOG"
+SQLITE_SRC_FILE="$(basename $SQLITE_SRC_URL)"
+curl -o "$SQLITE_SRC_FILE" $SQLITE_SRC_URL
+unzip "$SQLITE_SRC_FILE"
+
+# Paths and information in make output could be sensitive, so don't save in log.
+echo "Building..." | tee -a "$BUILD_LOG"
+pushd sqlite-src-*/
+./configure
+cd ext/wasm
+make dist
+popd
+
+echo "Copying files from sqlite-src-*/ext/wasm/ into build/" | tee -a "$BUILD_LOG"
+mkdir -p build/{common,jswasm} | tee -a "$BUILD_LOG"
+cp sqlite-src-*/ext/wasm/jswasm/speedtest1.{js,wasm} build/jswasm/ | tee -a "$BUILD_LOG"
+# The next files are only needed for the upstream browser build, not the
+# JetStream version, hence don't copy them by default.
+# cp sqlite-src-*/ext/wasm/speedtest1.html build/ | tee -a "$BUILD_LOG"
+# cp sqlite-src-*/ext/wasm/common/{emscripten.css,SqliteTestUtil.js,testing.css} build/common/ | tee -a "$BUILD_LOG"
+
+echo "Build success" | tee -a "$BUILD_LOG"
diff --git a/sqlite3/build/jswasm/speedtest1.js b/sqlite3/build/jswasm/speedtest1.js
new file mode 100644
index 0000000..ef21275
--- /dev/null
+++ b/sqlite3/build/jswasm/speedtest1.js
@@ -0,0 +1,17736 @@
+/*
+** LICENSE for the sqlite3 WebAssembly/JavaScript APIs.
+**
+** This bundle (typically released as sqlite3.js or sqlite3.mjs)
+** is an amalgamation of JavaScript source code from two projects:
+**
+** 1) https://emscripten.org: the Emscripten "glue code" is covered by
+** the terms of the MIT license and University of Illinois/NCSA
+** Open Source License, as described at:
+**
+** https://emscripten.org/docs/introducing_emscripten/emscripten_license.html
+**
+** 2) https://sqlite.org: all code and documentation labeled as being
+** from this source are released under the same terms as the sqlite3
+** C library:
+**
+** 2022-10-16
+**
+** The author disclaims copyright to this source code. In place of a
+** legal notice, here is a blessing:
+**
+** * May you do good and not evil.
+** * May you find forgiveness for yourself and forgive others.
+** * May you share freely, never taking more than you give.
+*/
+/*
+** This code was built from sqlite3 version...
+**
+** SQLITE_VERSION "3.47.1"
+** SQLITE_VERSION_NUMBER 3047001
+** SQLITE_SOURCE_ID "2024-11-25 12:07:48 b95d11e958643b969c47a8e5857f3793b9e69700b8f1469371386369a26e577e"
+**
+** Using the Emscripten SDK version 3.1.71.
+*/
+
+var sqlite3InitModule = (() => {
+ var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
+
+ return (
+function(moduleArg = {}) {
+ var moduleRtn;
+
+// include: shell.js
+// The Module object: Our interface to the outside world. We import
+// and export values on it. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(moduleArg) => Promise<Module>
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to check if Module already exists (e.g. case 3 above).
+// Substitution will be replaced with actual code on later stage of the build,
+// this way Closure Compiler will not mangle it (e.g. case 4. above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module = moduleArg;
+
+// Set up the promise that indicates the Module is initialized
+var readyPromiseResolve, readyPromiseReject;
+var readyPromise = new Promise((resolve, reject) => {
+ readyPromiseResolve = resolve;
+ readyPromiseReject = reject;
+});
+
+// Determine the runtime environment we are in. You can customize this by
+// setting the ENVIRONMENT setting at compile time (see settings.js).
+
+var ENVIRONMENT_IS_WEB = true;
+var ENVIRONMENT_IS_WORKER = false;
+var ENVIRONMENT_IS_NODE = false;
+var ENVIRONMENT_IS_SHELL = false;
+
+// --pre-jses are emitted after the Module integration code, so that they can
+// refer to Module (if they choose; they can also define Module)
+// include: /usr/local/google/home/dlehmann/JetStream/sqlite3/sqlite-src-3470100/ext/wasm/bld/pre-js.speedtest1-vanilla.js
+/**
+ BEGIN FILE: api/pre-js.js
+
+ This file is intended to be prepended to the sqlite3.js build using
+ Emscripten's --pre-js=THIS_FILE flag (or equivalent).
+*/
+
+// See notes in extern-post-js.js
+const sqlite3InitModuleState = globalThis.sqlite3InitModuleState
+ || Object.assign(Object.create(null),{
+ debugModule: ()=>{}
+ });
+delete globalThis.sqlite3InitModuleState;
+sqlite3InitModuleState.debugModule('globalThis.location =',globalThis.location);
+
+/**
+ This custom locateFile() tries to figure out where to load `path`
+ from. The intent is to provide a way for foo/bar/X.js loaded from a
+ Worker constructor or importScripts() to be able to resolve
+ foo/bar/X.wasm (in the latter case, with some help):
+
+ 1) If URL param named the same as `path` is set, it is returned.
+
+ 2) If sqlite3InitModuleState.sqlite3Dir is set, then (thatName + path)
+ is returned (note that it's assumed to end with '/').
+
+ 3) If this code is running in the main UI thread AND it was loaded
+ from a SCRIPT tag, the directory part of that URL is used
+ as the prefix. (This form of resolution unfortunately does not
+ function for scripts loaded via importScripts().)
+
+ 4) If none of the above apply, (prefix+path) is returned.
+*/
+Module['locateFile'] = function(path, prefix) {
+ 'use strict';
+ let theFile;
+ const up = this.urlParams;
+ if(up.has(path)){
+ theFile = up.get(path);
+ }else if(this.sqlite3Dir){
+ theFile = this.sqlite3Dir + path;
+ }else if(this.scriptDir){
+ theFile = this.scriptDir + path;
+ }else{
+ theFile = prefix + path;
+ }
+ this.debugModule(
+ "locateFile(",arguments[0], ',', arguments[1],")",
+ 'sqlite3InitModuleState.scriptDir =',this.scriptDir,
+ 'up.entries() =',Array.from(up.entries()),
+ "result =", theFile
+ );
+ return theFile;
+}.bind(sqlite3InitModuleState);
+
+/* END FILE: api/pre-js.js, noting that the build process may add a
+ line after this one to change the above .uri to a build-specific
+ one. */
+// end include: /usr/local/google/home/dlehmann/JetStream/sqlite3/sqlite-src-3470100/ext/wasm/bld/pre-js.speedtest1-vanilla.js
+
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = Object.assign({}, Module);
+
+var arguments_ = [];
+var thisProgram = './this.program';
+var quit_ = (status, toThrow) => {
+ throw toThrow;
+};
+
+// `/` should be present at the end if `scriptDirectory` is not empty
+var scriptDirectory = '';
+function locateFile(path) {
+ if (Module['locateFile']) {
+ return Module['locateFile'](path, scriptDirectory);
+ }
+ return scriptDirectory + path;
+}
+
+// Hooks that are implemented differently in different runtime environments.
+var readAsync, readBinary;
+
+// Note that this includes Node.js workers when relevant (pthreads is enabled).
+// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
+// ENVIRONMENT_IS_NODE.
+if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+ if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled
+ scriptDirectory = self.location.href;
+ } else if (typeof document != 'undefined' && document.currentScript) { // web
+ scriptDirectory = document.currentScript.src;
+ }
+ // When MODULARIZE, this JS may be executed later, after document.currentScript
+ // is gone, so we saved it, and we use it here instead of any other info.
+ if (_scriptName) {
+ scriptDirectory = _scriptName;
+ }
+ // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
+ // otherwise, slice off the final part of the url to find the script directory.
+ // if scriptDirectory does not contain a slash, lastIndexOf will return -1,
+ // and scriptDirectory will correctly be replaced with an empty string.
+ // If scriptDirectory contains a query (starting with ?) or a fragment (starting with #),
+ // they are removed because they could contain a slash.
+ if (scriptDirectory.startsWith('blob:')) {
+ scriptDirectory = '';
+ } else {
+ scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/')+1);
+ }
+
+ {
+// include: web_or_worker_shell_read.js
+readAsync = (url) => {
+ return fetch(url, { credentials: 'same-origin' })
+ .then((response) => {
+ if (response.ok) {
+ return response.arrayBuffer();
+ }
+ return Promise.reject(new Error(response.status + ' : ' + response.url));
+ })
+ };
+// end include: web_or_worker_shell_read.js
+ }
+} else
+{
+}
+
+var out = Module['print'] || console.log.bind(console);
+var err = Module['printErr'] || console.error.bind(console);
+
+// Merge back in the overrides
+Object.assign(Module, moduleOverrides);
+// Free the object hierarchy contained in the overrides, this lets the GC
+// reclaim data used.
+moduleOverrides = null;
+
+// Emit code to handle expected values on the Module object. This applies Module.x
+// to the proper local x. This has two benefits: first, we only emit it if it is
+// expected to arrive, and second, by using a local everywhere else that can be
+// minified.
+
+if (Module['arguments']) arguments_ = Module['arguments'];
+
+if (Module['thisProgram']) thisProgram = Module['thisProgram'];
+
+// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
+// end include: shell.js
+
+// include: preamble.js
+// === Preamble library stuff ===
+
+// Documentation for the public APIs defined in this file must be updated in:
+// site/source/docs/api_reference/preamble.js.rst
+// A prebuilt local version of the documentation is available at:
+// site/build/text/docs/api_reference/preamble.js.txt
+// You can also build docs locally as HTML or other formats in site/
+// An online HTML version (which may be of a different version of Emscripten)
+// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
+
+var wasmBinary = Module['wasmBinary'];
+
+// Wasm globals
+
+var wasmMemory;
+
+//========================================
+// Runtime essentials
+//========================================
+
+// whether we are quitting the application. no code should run after this.
+// set in exit() and abort()
+var ABORT = false;
+
+// set by exit() and abort(). Passed to 'onExit' handler.
+// NOTE: This is also used as the process return code code in shell environments
+// but only when noExitRuntime is false.
+var EXITSTATUS;
+
+// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we
+// don't define it at all in release modes. This matches the behaviour of
+// MINIMAL_RUNTIME.
+// TODO(sbc): Make this the default even without STRICT enabled.
+/** @type {function(*, string=)} */
+function assert(condition, text) {
+ if (!condition) {
+ // This build was created without ASSERTIONS defined. `assert()` should not
+ // ever be called in this configuration but in case there are callers in
+ // the wild leave this simple abort() implementation here for now.
+ abort(text);
+ }
+}
+
+// Memory management
+
+var HEAP,
+/** @type {!Int8Array} */
+ HEAP8,
+/** @type {!Uint8Array} */
+ HEAPU8,
+/** @type {!Int16Array} */
+ HEAP16,
+/** @type {!Uint16Array} */
+ HEAPU16,
+/** @type {!Int32Array} */
+ HEAP32,
+/** @type {!Uint32Array} */
+ HEAPU32,
+/** @type {!Float32Array} */
+ HEAPF32,
+/* BigInt64Array type is not correctly defined in closure
+/** not-@type {!BigInt64Array} */
+ HEAP64,
+/* BigUint64Array type is not correctly defined in closure
+/** not-t@type {!BigUint64Array} */
+ HEAPU64,
+/** @type {!Float64Array} */
+ HEAPF64;
+
+// include: runtime_shared.js
+function updateMemoryViews() {
+ var b = wasmMemory.buffer;
+ Module['HEAP8'] = HEAP8 = new Int8Array(b);
+ Module['HEAP16'] = HEAP16 = new Int16Array(b);
+ Module['HEAPU8'] = HEAPU8 = new Uint8Array(b);
+ Module['HEAPU16'] = HEAPU16 = new Uint16Array(b);
+ Module['HEAP32'] = HEAP32 = new Int32Array(b);
+ Module['HEAPU32'] = HEAPU32 = new Uint32Array(b);
+ Module['HEAPF32'] = HEAPF32 = new Float32Array(b);
+ Module['HEAPF64'] = HEAPF64 = new Float64Array(b);
+ Module['HEAP64'] = HEAP64 = new BigInt64Array(b);
+ Module['HEAPU64'] = HEAPU64 = new BigUint64Array(b);
+}
+
+// end include: runtime_shared.js
+// include: runtime_stack_check.js
+// end include: runtime_stack_check.js
+var __ATPRERUN__ = []; // functions called before the runtime is initialized
+var __ATINIT__ = []; // functions called during startup
+var __ATEXIT__ = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the main() is called
+
+var runtimeInitialized = false;
+
+function preRun() {
+ if (Module['preRun']) {
+ if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+ while (Module['preRun'].length) {
+ addOnPreRun(Module['preRun'].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function initRuntime() {
+ runtimeInitialized = true;
+
+
+if (!Module['noFSInit'] && !FS.initialized)
+ FS.init();
+FS.ignorePermissions = false;
+
+TTY.init();
+ callRuntimeCallbacks(__ATINIT__);
+}
+
+function postRun() {
+
+ if (Module['postRun']) {
+ if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+ while (Module['postRun'].length) {
+ addOnPostRun(Module['postRun'].shift());
+ }
+ }
+
+ callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+ __ATPRERUN__.unshift(cb);
+}
+
+function addOnInit(cb) {
+ __ATINIT__.unshift(cb);
+}
+
+function addOnExit(cb) {
+}
+
+function addOnPostRun(cb) {
+ __ATPOSTRUN__.unshift(cb);
+}
+
+// include: runtime_math.js
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
+
+// end include: runtime_math.js
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// Module.preRun (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function getUniqueRunDependency(id) {
+ return id;
+}
+
+function addRunDependency(id) {
+ runDependencies++;
+
+ Module['monitorRunDependencies']?.(runDependencies);
+
+}
+
+function removeRunDependency(id) {
+ runDependencies--;
+
+ Module['monitorRunDependencies']?.(runDependencies);
+
+ if (runDependencies == 0) {
+ if (runDependencyWatcher !== null) {
+ clearInterval(runDependencyWatcher);
+ runDependencyWatcher = null;
+ }
+ if (dependenciesFulfilled) {
+ var callback = dependenciesFulfilled;
+ dependenciesFulfilled = null;
+ callback(); // can add another dependenciesFulfilled
+ }
+ }
+}
+
+/** @param {string|number=} what */
+function abort(what) {
+ Module['onAbort']?.(what);
+
+ what = 'Aborted(' + what + ')';
+ // TODO(sbc): Should we remove printing and leave it up to whoever
+ // catches the exception?
+ err(what);
+
+ ABORT = true;
+
+ what += '. Build with -sASSERTIONS for more info.';
+
+ // Use a wasm runtime error, because a JS error might be seen as a foreign
+ // exception, which means we'd run destructors on it. We need the error to
+ // simply make the program stop.
+ // FIXME This approach does not work in Wasm EH because it currently does not assume
+ // all RuntimeErrors are from traps; it decides whether a RuntimeError is from
+ // a trap or not based on a hidden field within the object. So at the moment
+ // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that
+ // allows this in the wasm spec.
+
+ // Suppress closure compiler warning here. Closure compiler's builtin extern
+ // definition for WebAssembly.RuntimeError claims it takes no arguments even
+ // though it can.
+ // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
+ /** @suppress {checkTypes} */
+ var e = new WebAssembly.RuntimeError(what);
+
+ readyPromiseReject(e);
+ // Throw the error whether or not MODULARIZE is set because abort is used
+ // in code paths apart from instantiation where an exception is expected
+ // to be thrown when abort is called.
+ throw e;
+}
+
+// include: memoryprofiler.js
+// end include: memoryprofiler.js
+// include: URIUtils.js
+// Prefix of data URIs emitted by SINGLE_FILE and related options.
+var dataURIPrefix = 'data:application/octet-stream;base64,';
+
+/**
+ * Indicates whether filename is a base64 data URI.
+ * @noinline
+ */
+var isDataURI = (filename) => filename.startsWith(dataURIPrefix);
+
+/**
+ * Indicates whether filename is delivered via file protocol (as opposed to http/https)
+ * @noinline
+ */
+var isFileURI = (filename) => filename.startsWith('file://');
+// end include: URIUtils.js
+// include: runtime_exceptions.js
+// end include: runtime_exceptions.js
+function findWasmBinary() {
+ var f = 'speedtest1.wasm';
+ if (!isDataURI(f)) {
+ return locateFile(f);
+ }
+ return f;
+}
+
+var wasmBinaryFile;
+
+function getBinarySync(file) {
+ if (file == wasmBinaryFile && wasmBinary) {
+ return new Uint8Array(wasmBinary);
+ }
+ if (readBinary) {
+ return readBinary(file);
+ }
+ throw 'both async and sync fetching of the wasm failed';
+}
+
+function getBinaryPromise(binaryFile) {
+ // If we don't have the binary yet, load it asynchronously using readAsync.
+ if (!wasmBinary
+ ) {
+ // Fetch the binary using readAsync
+ return readAsync(binaryFile).then(
+ (response) => new Uint8Array(/** @type{!ArrayBuffer} */(response)),
+ // Fall back to getBinarySync if readAsync fails
+ () => getBinarySync(binaryFile)
+ );
+ }
+
+ // Otherwise, getBinarySync should be able to get it synchronously
+ return Promise.resolve().then(() => getBinarySync(binaryFile));
+}
+
+function instantiateArrayBuffer(binaryFile, imports, receiver) {
+ return getBinaryPromise(binaryFile).then((binary) => {
+ return WebAssembly.instantiate(binary, imports);
+ }).then(receiver, (reason) => {
+ err(`failed to asynchronously prepare wasm: ${reason}`);
+
+ abort(reason);
+ });
+}
+
+function instantiateAsync(binary, binaryFile, imports, callback) {
+ if (!binary &&
+ typeof WebAssembly.instantiateStreaming == 'function' &&
+ !isDataURI(binaryFile) &&
+ typeof fetch == 'function') {
+ return fetch(binaryFile, { credentials: 'same-origin' }).then((response) => {
+ // Suppress closure warning here since the upstream definition for
+ // instantiateStreaming only allows Promise<Repsponse> rather than
+ // an actual Response.
+ // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed.
+ /** @suppress {checkTypes} */
+ var result = WebAssembly.instantiateStreaming(response, imports);
+
+ return result.then(
+ callback,
+ function(reason) {
+ // We expect the most common failure cause to be a bad MIME type for the binary,
+ // in which case falling back to ArrayBuffer instantiation should work.
+ err(`wasm streaming compile failed: ${reason}`);
+ err('falling back to ArrayBuffer instantiation');
+ return instantiateArrayBuffer(binaryFile, imports, callback);
+ });
+ });
+ }
+ return instantiateArrayBuffer(binaryFile, imports, callback);
+}
+
+function getWasmImports() {
+ // prepare imports
+ return {
+ 'env': wasmImports,
+ 'wasi_snapshot_preview1': wasmImports,
+ }
+}
+
+// Create the wasm instance.
+// Receives the wasm imports, returns the exports.
+function createWasm() {
+ var info = getWasmImports();
+ // Load the wasm module and create an instance of using native support in the JS engine.
+ // handle a generated wasm instance, receiving its exports and
+ // performing other necessary setup
+ /** @param {WebAssembly.Module=} module*/
+ function receiveInstance(instance, module) {
+ wasmExports = instance.exports;
+
+
+
+ wasmMemory = wasmExports['memory'];
+ Module['wasmMemory'] = wasmMemory;
+ updateMemoryViews();
+
+ addOnInit(wasmExports['__wasm_call_ctors']);
+
+ removeRunDependency('wasm-instantiate');
+ return wasmExports;
+ }
+ // wait for the pthread pool (if any)
+ addRunDependency('wasm-instantiate');
+
+ // Prefer streaming instantiation if available.
+ function receiveInstantiationResult(result) {
+ // 'result' is a ResultObject object which has both the module and instance.
+ // receiveInstance() will swap in the exports (to Module.asm) so they can be called
+ // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
+ // When the regression is fixed, can restore the above PTHREADS-enabled path.
+ receiveInstance(result['instance']);
+ }
+
+ // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
+ // to manually instantiate the Wasm module themselves. This allows pages to
+ // run the instantiation parallel to any other async startup actions they are
+ // performing.
+ // Also pthreads and wasm workers initialize the wasm instance through this
+ // path.
+ if (Module['instantiateWasm']) {
+ try {
+ return Module['instantiateWasm'](info, receiveInstance);
+ } catch(e) {
+ err(`Module.instantiateWasm callback failed with error: ${e}`);
+ // If instantiation fails, reject the module ready promise.
+ readyPromiseReject(e);
+ }
+ }
+
+ wasmBinaryFile ??= findWasmBinary();
+
+ // If instantiation fails, reject the module ready promise.
+ instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject);
+ return {}; // no exports yet; we'll fill them in later
+}
+
+// include: runtime_debug.js
+// end include: runtime_debug.js
+// === Body ===
+// end include: preamble.js
+
+
+ class ExitStatus {
+ name = 'ExitStatus';
+ constructor(status) {
+ this.message = `Program terminated with exit(${status})`;
+ this.status = status;
+ }
+ }
+
+ var callRuntimeCallbacks = (callbacks) => {
+ while (callbacks.length > 0) {
+ // Pass the module as the first argument.
+ callbacks.shift()(Module);
+ }
+ };
+
+
+ /**
+ * @param {number} ptr
+ * @param {string} type
+ */
+ function getValue(ptr, type = 'i8') {
+ if (type.endsWith('*')) type = '*';
+ switch (type) {
+ case 'i1': return HEAP8[ptr];
+ case 'i8': return HEAP8[ptr];
+ case 'i16': return HEAP16[((ptr)>>1)];
+ case 'i32': return HEAP32[((ptr)>>2)];
+ case 'i64': return HEAP64[((ptr)>>3)];
+ case 'float': return HEAPF32[((ptr)>>2)];
+ case 'double': return HEAPF64[((ptr)>>3)];
+ case '*': return HEAPU32[((ptr)>>2)];
+ default: abort(`invalid type for getValue: ${type}`);
+ }
+ }
+
+ var noExitRuntime = Module['noExitRuntime'] || true;
+
+
+ /**
+ * @param {number} ptr
+ * @param {number} value
+ * @param {string} type
+ */
+ function setValue(ptr, value, type = 'i8') {
+ if (type.endsWith('*')) type = '*';
+ switch (type) {
+ case 'i1': HEAP8[ptr] = value; break;
+ case 'i8': HEAP8[ptr] = value; break;
+ case 'i16': HEAP16[((ptr)>>1)] = value; break;
+ case 'i32': HEAP32[((ptr)>>2)] = value; break;
+ case 'i64': HEAP64[((ptr)>>3)] = BigInt(value); break;
+ case 'float': HEAPF32[((ptr)>>2)] = value; break;
+ case 'double': HEAPF64[((ptr)>>3)] = value; break;
+ case '*': HEAPU32[((ptr)>>2)] = value; break;
+ default: abort(`invalid type for setValue: ${type}`);
+ }
+ }
+
+ var stackRestore = (val) => __emscripten_stack_restore(val);
+
+ var stackSave = () => _emscripten_stack_get_current();
+
+ var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined;
+
+ /**
+ * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given
+ * array that contains uint8 values, returns a copy of that string as a
+ * Javascript String object.
+ * heapOrArray is either a regular array, or a JavaScript typed array view.
+ * @param {number=} idx
+ * @param {number=} maxBytesToRead
+ * @return {string}
+ */
+ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => {
+ var endIdx = idx + maxBytesToRead;
+ var endPtr = idx;
+ // TextDecoder needs to know the byte length in advance, it doesn't stop on
+ // null terminator by itself. Also, use the length info to avoid running tiny
+ // strings through TextDecoder, since .subarray() allocates garbage.
+ // (As a tiny code save trick, compare endPtr against endIdx using a negation,
+ // so that undefined/NaN means Infinity)
+ while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
+
+ if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
+ return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
+ }
+ var str = '';
+ // If building with TextDecoder, we have already computed the string length
+ // above, so test loop end condition against that
+ while (idx < endPtr) {
+ // For UTF8 byte structure, see:
+ // http://en.wikipedia.org/wiki/UTF-8#Description
+ // https://www.ietf.org/rfc/rfc2279.txt
+ // https://tools.ietf.org/html/rfc3629
+ var u0 = heapOrArray[idx++];
+ if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
+ var u1 = heapOrArray[idx++] & 63;
+ if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
+ var u2 = heapOrArray[idx++] & 63;
+ if ((u0 & 0xF0) == 0xE0) {
+ u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
+ } else {
+ u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
+ }
+
+ if (u0 < 0x10000) {
+ str += String.fromCharCode(u0);
+ } else {
+ var ch = u0 - 0x10000;
+ str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+ }
+ }
+ return str;
+ };
+
+ /**
+ * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the
+ * emscripten HEAP, returns a copy of that string as a Javascript String object.
+ *
+ * @param {number} ptr
+ * @param {number=} maxBytesToRead - An optional length that specifies the
+ * maximum number of bytes to read. You can omit this parameter to scan the
+ * string until the first 0 byte. If maxBytesToRead is passed, and the string
+ * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the
+ * string will cut short at that byte index (i.e. maxBytesToRead will not
+ * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing
+ * frequent uses of UTF8ToString() with and without maxBytesToRead may throw
+ * JS JIT optimizations off, so it is worth to consider consistently using one
+ * @return {string}
+ */
+ var UTF8ToString = (ptr, maxBytesToRead) => {
+ return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : '';
+ };
+ var ___assert_fail = (condition, filename, line, func) => {
+ abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']);
+ };
+
+ var PATH = {
+ isAbs:(path) => path.charAt(0) === '/',
+ splitPath:(filename) => {
+ var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+ return splitPathRe.exec(filename).slice(1);
+ },
+ normalizeArray:(parts, allowAboveRoot) => {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === '.') {
+ parts.splice(i, 1);
+ } else if (last === '..') {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (; up; up--) {
+ parts.unshift('..');
+ }
+ }
+ return parts;
+ },
+ normalize:(path) => {
+ var isAbsolute = PATH.isAbs(path),
+ trailingSlash = path.substr(-1) === '/';
+ // Normalize the path
+ path = PATH.normalizeArray(path.split('/').filter((p) => !!p), !isAbsolute).join('/');
+ if (!path && !isAbsolute) {
+ path = '.';
+ }
+ if (path && trailingSlash) {
+ path += '/';
+ }
+ return (isAbsolute ? '/' : '') + path;
+ },
+ dirname:(path) => {
+ var result = PATH.splitPath(path),
+ root = result[0],
+ dir = result[1];
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return '.';
+ }
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+ return root + dir;
+ },
+ basename:(path) => {
+ // EMSCRIPTEN return '/'' for '/', not an empty string
+ if (path === '/') return '/';
+ path = PATH.normalize(path);
+ path = path.replace(/\/$/, "");
+ var lastSlash = path.lastIndexOf('/');
+ if (lastSlash === -1) return path;
+ return path.substr(lastSlash+1);
+ },
+ join:(...paths) => PATH.normalize(paths.join('/')),
+ join2:(l, r) => PATH.normalize(l + '/' + r),
+ };
+
+ var initRandomFill = () => {
+ if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') {
+ // for modern web browsers
+ return (view) => crypto.getRandomValues(view);
+ } else
+ // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096
+ abort('initRandomDevice');
+ };
+ var randomFill = (view) => {
+ // Lazily init on the first invocation.
+ return (randomFill = initRandomFill())(view);
+ };
+
+
+
+ var PATH_FS = {
+ resolve:(...args) => {
+ var resolvedPath = '',
+ resolvedAbsolute = false;
+ for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? args[i] : FS.cwd();
+ // Skip empty and invalid entries
+ if (typeof path != 'string') {
+ throw new TypeError('Arguments to path.resolve must be strings');
+ } else if (!path) {
+ return ''; // an invalid portion invalidates the whole thing
+ }
+ resolvedPath = path + '/' + resolvedPath;
+ resolvedAbsolute = PATH.isAbs(path);
+ }
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+ resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter((p) => !!p), !resolvedAbsolute).join('/');
+ return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+ },
+ relative:(from, to) => {
+ from = PATH_FS.resolve(from).substr(1);
+ to = PATH_FS.resolve(to).substr(1);
+ function trim(arr) {
+ var start = 0;
+ for (; start < arr.length; start++) {
+ if (arr[start] !== '') break;
+ }
+ var end = arr.length - 1;
+ for (; end >= 0; end--) {
+ if (arr[end] !== '') break;
+ }
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+ var fromParts = trim(from.split('/'));
+ var toParts = trim(to.split('/'));
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push('..');
+ }
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+ return outputParts.join('/');
+ },
+ };
+
+
+
+ var FS_stdin_getChar_buffer = [];
+
+ var lengthBytesUTF8 = (str) => {
+ var len = 0;
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
+ // unit, not a Unicode code point of the character! So decode
+ // UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ var c = str.charCodeAt(i); // possibly a lead surrogate
+ if (c <= 0x7F) {
+ len++;
+ } else if (c <= 0x7FF) {
+ len += 2;
+ } else if (c >= 0xD800 && c <= 0xDFFF) {
+ len += 4; ++i;
+ } else {
+ len += 3;
+ }
+ }
+ return len;
+ };
+
+ var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
+ // Parameter maxBytesToWrite is not optional. Negative values, 0, null,
+ // undefined and false each don't write out any bytes.
+ if (!(maxBytesToWrite > 0))
+ return 0;
+
+ var startIdx = outIdx;
+ var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator.
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
+ // unit, not a Unicode code point of the character! So decode
+ // UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description
+ // and https://www.ietf.org/rfc/rfc2279.txt
+ // and https://tools.ietf.org/html/rfc3629
+ var u = str.charCodeAt(i); // possibly a lead surrogate
+ if (u >= 0xD800 && u <= 0xDFFF) {
+ var u1 = str.charCodeAt(++i);
+ u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF);
+ }
+ if (u <= 0x7F) {
+ if (outIdx >= endIdx) break;
+ heap[outIdx++] = u;
+ } else if (u <= 0x7FF) {
+ if (outIdx + 1 >= endIdx) break;
+ heap[outIdx++] = 0xC0 | (u >> 6);
+ heap[outIdx++] = 0x80 | (u & 63);
+ } else if (u <= 0xFFFF) {
+ if (outIdx + 2 >= endIdx) break;
+ heap[outIdx++] = 0xE0 | (u >> 12);
+ heap[outIdx++] = 0x80 | ((u >> 6) & 63);
+ heap[outIdx++] = 0x80 | (u & 63);
+ } else {
+ if (outIdx + 3 >= endIdx) break;
+ heap[outIdx++] = 0xF0 | (u >> 18);
+ heap[outIdx++] = 0x80 | ((u >> 12) & 63);
+ heap[outIdx++] = 0x80 | ((u >> 6) & 63);
+ heap[outIdx++] = 0x80 | (u & 63);
+ }
+ }
+ // Null-terminate the pointer to the buffer.
+ heap[outIdx] = 0;
+ return outIdx - startIdx;
+ };
+ /** @type {function(string, boolean=, number=)} */
+ function intArrayFromString(stringy, dontAddNull, length) {
+ var len = length > 0 ? length : lengthBytesUTF8(stringy)+1;
+ var u8array = new Array(len);
+ var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
+ if (dontAddNull) u8array.length = numBytesWritten;
+ return u8array;
+ }
+ var FS_stdin_getChar = () => {
+ if (!FS_stdin_getChar_buffer.length) {
+ var result = null;
+ if (typeof window != 'undefined' &&
+ typeof window.prompt == 'function') {
+ // Browser.
+ result = window.prompt('Input: '); // returns null on cancel
+ if (result !== null) {
+ result += '\n';
+ }
+ } else
+ {}
+ if (!result) {
+ return null;
+ }
+ FS_stdin_getChar_buffer = intArrayFromString(result, true);
+ }
+ return FS_stdin_getChar_buffer.shift();
+ };
+ var TTY = {
+ ttys:[],
+ init() {
+ // https://github.com/emscripten-core/emscripten/pull/1555
+ // if (ENVIRONMENT_IS_NODE) {
+ // // currently, FS.init does not distinguish if process.stdin is a file or TTY
+ // // device, it always assumes it's a TTY device. because of this, we're forcing
+ // // process.stdin to UTF8 encoding to at least make stdin reading compatible
+ // // with text files until FS.init can be refactored.
+ // process.stdin.setEncoding('utf8');
+ // }
+ },
+ shutdown() {
+ // https://github.com/emscripten-core/emscripten/pull/1555
+ // if (ENVIRONMENT_IS_NODE) {
+ // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+ // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+ // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+ // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+ // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+ // process.stdin.pause();
+ // }
+ },
+ register(dev, ops) {
+ TTY.ttys[dev] = { input: [], output: [], ops: ops };
+ FS.registerDevice(dev, TTY.stream_ops);
+ },
+ stream_ops:{
+ open(stream) {
+ var tty = TTY.ttys[stream.node.rdev];
+ if (!tty) {
+ throw new FS.ErrnoError(43);
+ }
+ stream.tty = tty;
+ stream.seekable = false;
+ },
+ close(stream) {
+ // flush any pending line data
+ stream.tty.ops.fsync(stream.tty);
+ },
+ fsync(stream) {
+ stream.tty.ops.fsync(stream.tty);
+ },
+ read(stream, buffer, offset, length, pos /* ignored */) {
+ if (!stream.tty || !stream.tty.ops.get_char) {
+ throw new FS.ErrnoError(60);
+ }
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = stream.tty.ops.get_char(stream.tty);
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(6);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset+i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, pos) {
+ if (!stream.tty || !stream.tty.ops.put_char) {
+ throw new FS.ErrnoError(60);
+ }
+ try {
+ for (var i = 0; i < length; i++) {
+ stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+ }
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ },
+ },
+ default_tty_ops:{
+ get_char(tty) {
+ return FS_stdin_getChar();
+ },
+ put_char(tty, val) {
+ if (val === null || val === 10) {
+ out(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ } else {
+ if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle.
+ }
+ },
+ fsync(tty) {
+ if (tty.output && tty.output.length > 0) {
+ out(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ }
+ },
+ ioctl_tcgets(tty) {
+ // typical setting
+ return {
+ c_iflag: 25856,
+ c_oflag: 5,
+ c_cflag: 191,
+ c_lflag: 35387,
+ c_cc: [
+ 0x03, 0x1c, 0x7f, 0x15, 0x04, 0x00, 0x01, 0x00, 0x11, 0x13, 0x1a, 0x00,
+ 0x12, 0x0f, 0x17, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ]
+ };
+ },
+ ioctl_tcsets(tty, optional_actions, data) {
+ // currently just ignore
+ return 0;
+ },
+ ioctl_tiocgwinsz(tty) {
+ return [24, 80];
+ },
+ },
+ default_tty1_ops:{
+ put_char(tty, val) {
+ if (val === null || val === 10) {
+ err(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ } else {
+ if (val != 0) tty.output.push(val);
+ }
+ },
+ fsync(tty) {
+ if (tty.output && tty.output.length > 0) {
+ err(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ }
+ },
+ },
+ };
+
+
+ var zeroMemory = (address, size) => {
+ HEAPU8.fill(0, address, address + size);
+ };
+
+ var alignMemory = (size, alignment) => {
+ return Math.ceil(size / alignment) * alignment;
+ };
+ var mmapAlloc = (size) => {
+ size = alignMemory(size, 65536);
+ var ptr = _emscripten_builtin_memalign(65536, size);
+ if (ptr) zeroMemory(ptr, size);
+ return ptr;
+ };
+ var MEMFS = {
+ ops_table:null,
+ mount(mount) {
+ return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+ },
+ createNode(parent, name, mode, dev) {
+ if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+ // no supported
+ throw new FS.ErrnoError(63);
+ }
+ MEMFS.ops_table ||= {
+ dir: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ lookup: MEMFS.node_ops.lookup,
+ mknod: MEMFS.node_ops.mknod,
+ rename: MEMFS.node_ops.rename,
+ unlink: MEMFS.node_ops.unlink,
+ rmdir: MEMFS.node_ops.rmdir,
+ readdir: MEMFS.node_ops.readdir,
+ symlink: MEMFS.node_ops.symlink
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek
+ }
+ },
+ file: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek,
+ read: MEMFS.stream_ops.read,
+ write: MEMFS.stream_ops.write,
+ allocate: MEMFS.stream_ops.allocate,
+ mmap: MEMFS.stream_ops.mmap,
+ msync: MEMFS.stream_ops.msync
+ }
+ },
+ link: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ readlink: MEMFS.node_ops.readlink
+ },
+ stream: {}
+ },
+ chrdev: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: FS.chrdev_stream_ops
+ }
+ };
+ var node = FS.createNode(parent, name, mode, dev);
+ if (FS.isDir(node.mode)) {
+ node.node_ops = MEMFS.ops_table.dir.node;
+ node.stream_ops = MEMFS.ops_table.dir.stream;
+ node.contents = {};
+ } else if (FS.isFile(node.mode)) {
+ node.node_ops = MEMFS.ops_table.file.node;
+ node.stream_ops = MEMFS.ops_table.file.stream;
+ node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.
+ // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred
+ // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size
+ // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme.
+ node.contents = null;
+ } else if (FS.isLink(node.mode)) {
+ node.node_ops = MEMFS.ops_table.link.node;
+ node.stream_ops = MEMFS.ops_table.link.stream;
+ } else if (FS.isChrdev(node.mode)) {
+ node.node_ops = MEMFS.ops_table.chrdev.node;
+ node.stream_ops = MEMFS.ops_table.chrdev.stream;
+ }
+ node.timestamp = Date.now();
+ // add the new node to the parent
+ if (parent) {
+ parent.contents[name] = node;
+ parent.timestamp = node.timestamp;
+ }
+ return node;
+ },
+ getFileDataAsTypedArray(node) {
+ if (!node.contents) return new Uint8Array(0);
+ if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes.
+ return new Uint8Array(node.contents);
+ },
+ expandFileStorage(node, newCapacity) {
+ var prevCapacity = node.contents ? node.contents.length : 0;
+ if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough.
+ // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity.
+ // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to
+ // avoid overshooting the allocation cap by a very large margin.
+ var CAPACITY_DOUBLING_MAX = 1024 * 1024;
+ newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> 0);
+ if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding.
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newCapacity); // Allocate new storage.
+ if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage.
+ },
+ resizeFileStorage(node, newSize) {
+ if (node.usedBytes == newSize) return;
+ if (newSize == 0) {
+ node.contents = null; // Fully decommit when requesting a resize to zero.
+ node.usedBytes = 0;
+ } else {
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newSize); // Allocate new storage.
+ if (oldContents) {
+ node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage.
+ }
+ node.usedBytes = newSize;
+ }
+ },
+ node_ops:{
+ getattr(node) {
+ var attr = {};
+ // device numbers reuse inode numbers.
+ attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+ attr.ino = node.id;
+ attr.mode = node.mode;
+ attr.nlink = 1;
+ attr.uid = 0;
+ attr.gid = 0;
+ attr.rdev = node.rdev;
+ if (FS.isDir(node.mode)) {
+ attr.size = 4096;
+ } else if (FS.isFile(node.mode)) {
+ attr.size = node.usedBytes;
+ } else if (FS.isLink(node.mode)) {
+ attr.size = node.link.length;
+ } else {
+ attr.size = 0;
+ }
+ attr.atime = new Date(node.timestamp);
+ attr.mtime = new Date(node.timestamp);
+ attr.ctime = new Date(node.timestamp);
+ // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+ // but this is not required by the standard.
+ attr.blksize = 4096;
+ attr.blocks = Math.ceil(attr.size / attr.blksize);
+ return attr;
+ },
+ setattr(node, attr) {
+ if (attr.mode !== undefined) {
+ node.mode = attr.mode;
+ }
+ if (attr.timestamp !== undefined) {
+ node.timestamp = attr.timestamp;
+ }
+ if (attr.size !== undefined) {
+ MEMFS.resizeFileStorage(node, attr.size);
+ }
+ },
+ lookup(parent, name) {
+ throw FS.genericErrors[44];
+ },
+ mknod(parent, name, mode, dev) {
+ return MEMFS.createNode(parent, name, mode, dev);
+ },
+ rename(old_node, new_dir, new_name) {
+ // if we're overwriting a directory at new_name, make sure it's empty.
+ if (FS.isDir(old_node.mode)) {
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {
+ }
+ if (new_node) {
+ for (var i in new_node.contents) {
+ throw new FS.ErrnoError(55);
+ }
+ }
+ }
+ // do the internal rewiring
+ delete old_node.parent.contents[old_node.name];
+ old_node.parent.timestamp = Date.now()
+ old_node.name = new_name;
+ new_dir.contents[new_name] = old_node;
+ new_dir.timestamp = old_node.parent.timestamp;
+ },
+ unlink(parent, name) {
+ delete parent.contents[name];
+ parent.timestamp = Date.now();
+ },
+ rmdir(parent, name) {
+ var node = FS.lookupNode(parent, name);
+ for (var i in node.contents) {
+ throw new FS.ErrnoError(55);
+ }
+ delete parent.contents[name];
+ parent.timestamp = Date.now();
+ },
+ readdir(node) {
+ var entries = ['.', '..'];
+ for (var key of Object.keys(node.contents)) {
+ entries.push(key);
+ }
+ return entries;
+ },
+ symlink(parent, newname, oldpath) {
+ var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+ node.link = oldpath;
+ return node;
+ },
+ readlink(node) {
+ if (!FS.isLink(node.mode)) {
+ throw new FS.ErrnoError(28);
+ }
+ return node.link;
+ },
+ },
+ stream_ops:{
+ read(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ if (position >= stream.node.usedBytes) return 0;
+ var size = Math.min(stream.node.usedBytes - position, length);
+ if (size > 8 && contents.subarray) { // non-trivial, and typed array
+ buffer.set(contents.subarray(position, position + size), offset);
+ } else {
+ for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
+ }
+ return size;
+ },
+ write(stream, buffer, offset, length, position, canOwn) {
+ // If the buffer is located in main memory (HEAP), and if
+ // memory can grow, we can't hold on to references of the
+ // memory buffer, as they may get invalidated. That means we
+ // need to do copy its contents.
+ if (buffer.buffer === HEAP8.buffer) {
+ canOwn = false;
+ }
+
+ if (!length) return 0;
+ var node = stream.node;
+ node.timestamp = Date.now();
+
+ if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array?
+ if (canOwn) {
+ node.contents = buffer.subarray(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (node.usedBytes === 0 && position === 0) { // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data.
+ node.contents = buffer.slice(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file?
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ return length;
+ }
+ }
+
+ // Appending to an existing file and we need to reallocate, or source data did not come as a typed array.
+ MEMFS.expandFileStorage(node, position+length);
+ if (node.contents.subarray && buffer.subarray) {
+ // Use typed array write which is available.
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ } else {
+ for (var i = 0; i < length; i++) {
+ node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not.
+ }
+ }
+ node.usedBytes = Math.max(node.usedBytes, position + length);
+ return length;
+ },
+ llseek(stream, offset, whence) {
+ var position = offset;
+ if (whence === 1) {
+ position += stream.position;
+ } else if (whence === 2) {
+ if (FS.isFile(stream.node.mode)) {
+ position += stream.node.usedBytes;
+ }
+ }
+ if (position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ return position;
+ },
+ allocate(stream, offset, length) {
+ MEMFS.expandFileStorage(stream.node, offset + length);
+ stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);
+ },
+ mmap(stream, length, position, prot, flags) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ var ptr;
+ var allocated;
+ var contents = stream.node.contents;
+ // Only make a new copy when MAP_PRIVATE is specified.
+ if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) {
+ // We can't emulate MAP_SHARED when the file is not backed by the
+ // buffer we're mapping to (e.g. the HEAP buffer).
+ allocated = false;
+ ptr = contents.byteOffset;
+ } else {
+ allocated = true;
+ ptr = mmapAlloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(48);
+ }
+ if (contents) {
+ // Try to avoid unnecessary slices.
+ if (position > 0 || position + length < contents.length) {
+ if (contents.subarray) {
+ contents = contents.subarray(position, position + length);
+ } else {
+ contents = Array.prototype.slice.call(contents, position, position + length);
+ }
+ }
+ HEAP8.set(contents, ptr);
+ }
+ }
+ return { ptr, allocated };
+ },
+ msync(stream, buffer, offset, length, mmapFlags) {
+ MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
+ // should we check if bytesWritten and length are the same?
+ return 0;
+ },
+ },
+ };
+
+ /** @param {boolean=} noRunDep */
+ var asyncLoad = (url, onload, onerror, noRunDep) => {
+ var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : '';
+ readAsync(url).then(
+ (arrayBuffer) => {
+ onload(new Uint8Array(arrayBuffer));
+ if (dep) removeRunDependency(dep);
+ },
+ (err) => {
+ if (onerror) {
+ onerror();
+ } else {
+ throw `Loading data file "${url}" failed.`;
+ }
+ }
+ );
+ if (dep) addRunDependency(dep);
+ };
+
+
+ var FS_createDataFile = (parent, name, fileData, canRead, canWrite, canOwn) => {
+ FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn);
+ };
+
+ var preloadPlugins = Module['preloadPlugins'] || [];
+ var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => {
+ // Ensure plugins are ready.
+ if (typeof Browser != 'undefined') Browser.init();
+
+ var handled = false;
+ preloadPlugins.forEach((plugin) => {
+ if (handled) return;
+ if (plugin['canHandle'](fullname)) {
+ plugin['handle'](byteArray, fullname, finish, onerror);
+ handled = true;
+ }
+ });
+ return handled;
+ };
+ var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => {
+ // TODO we should allow people to just pass in a complete filename instead
+ // of parent and name being that we just join them anyways
+ var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent;
+ var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname
+ function processData(byteArray) {
+ function finish(byteArray) {
+ preFinish?.();
+ if (!dontCreateFile) {
+ FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+ }
+ onload?.();
+ removeRunDependency(dep);
+ }
+ if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => {
+ onerror?.();
+ removeRunDependency(dep);
+ })) {
+ return;
+ }
+ finish(byteArray);
+ }
+ addRunDependency(dep);
+ if (typeof url == 'string') {
+ asyncLoad(url, processData, onerror);
+ } else {
+ processData(url);
+ }
+ };
+
+ var FS_modeStringToFlags = (str) => {
+ var flagModes = {
+ 'r': 0,
+ 'r+': 2,
+ 'w': 512 | 64 | 1,
+ 'w+': 512 | 64 | 2,
+ 'a': 1024 | 64 | 1,
+ 'a+': 1024 | 64 | 2,
+ };
+ var flags = flagModes[str];
+ if (typeof flags == 'undefined') {
+ throw new Error(`Unknown file open mode: ${str}`);
+ }
+ return flags;
+ };
+
+ var FS_getMode = (canRead, canWrite) => {
+ var mode = 0;
+ if (canRead) mode |= 292 | 73;
+ if (canWrite) mode |= 146;
+ return mode;
+ };
+
+
+
+ var FS = {
+ root:null,
+ mounts:[],
+ devices:{
+ },
+ streams:[],
+ nextInode:1,
+ nameTable:null,
+ currentPath:"/",
+ initialized:false,
+ ignorePermissions:true,
+ ErrnoError:class {
+ name = 'ErrnoError';
+ // We set the `name` property to be able to identify `FS.ErrnoError`
+ // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway.
+ // - when using PROXYFS, an error can come from an underlying FS
+ // as different FS objects have their own FS.ErrnoError each,
+ // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs.
+ // we'll use the reliable test `err.name == "ErrnoError"` instead
+ constructor(errno) {
+ this.errno = errno;
+ }
+ },
+ genericErrors:{
+ },
+ filesystems:null,
+ syncFSRequests:0,
+ readFiles:{
+ },
+ FSStream:class {
+ shared = {};
+ get object() {
+ return this.node;
+ }
+ set object(val) {
+ this.node = val;
+ }
+ get isRead() {
+ return (this.flags & 2097155) !== 1;
+ }
+ get isWrite() {
+ return (this.flags & 2097155) !== 0;
+ }
+ get isAppend() {
+ return (this.flags & 1024);
+ }
+ get flags() {
+ return this.shared.flags;
+ }
+ set flags(val) {
+ this.shared.flags = val;
+ }
+ get position() {
+ return this.shared.position;
+ }
+ set position(val) {
+ this.shared.position = val;
+ }
+ },
+ FSNode:class {
+ node_ops = {};
+ stream_ops = {};
+ readMode = 292 | 73;
+ writeMode = 146;
+ mounted = null;
+ constructor(parent, name, mode, rdev) {
+ if (!parent) {
+ parent = this; // root node sets parent to itself
+ }
+ this.parent = parent;
+ this.mount = parent.mount;
+ this.id = FS.nextInode++;
+ this.name = name;
+ this.mode = mode;
+ this.rdev = rdev;
+ }
+ get read() {
+ return (this.mode & this.readMode) === this.readMode;
+ }
+ set read(val) {
+ val ? this.mode |= this.readMode : this.mode &= ~this.readMode;
+ }
+ get write() {
+ return (this.mode & this.writeMode) === this.writeMode;
+ }
+ set write(val) {
+ val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode;
+ }
+ get isFolder() {
+ return FS.isDir(this.mode);
+ }
+ get isDevice() {
+ return FS.isChrdev(this.mode);
+ }
+ },
+ lookupPath(path, opts = {}) {
+ path = PATH_FS.resolve(path);
+
+ if (!path) return { path: '', node: null };
+
+ var defaults = {
+ follow_mount: true,
+ recurse_count: 0
+ };
+ opts = Object.assign(defaults, opts)
+
+ if (opts.recurse_count > 8) { // max recursive lookup of 8
+ throw new FS.ErrnoError(32);
+ }
+
+ // split the absolute path
+ var parts = path.split('/').filter((p) => !!p);
+
+ // start at the root
+ var current = FS.root;
+ var current_path = '/';
+
+ for (var i = 0; i < parts.length; i++) {
+ var islast = (i === parts.length-1);
+ if (islast && opts.parent) {
+ // stop resolving
+ break;
+ }
+
+ current = FS.lookupNode(current, parts[i]);
+ current_path = PATH.join2(current_path, parts[i]);
+
+ // jump to the mount's root node if this is a mountpoint
+ if (FS.isMountpoint(current)) {
+ if (!islast || (islast && opts.follow_mount)) {
+ current = current.mounted.root;
+ }
+ }
+
+ // by default, lookupPath will not follow a symlink if it is the final path component.
+ // setting opts.follow = true will override this behavior.
+ if (!islast || opts.follow) {
+ var count = 0;
+ while (FS.isLink(current.mode)) {
+ var link = FS.readlink(current_path);
+ current_path = PATH_FS.resolve(PATH.dirname(current_path), link);
+
+ var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count + 1 });
+ current = lookup.node;
+
+ if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+ throw new FS.ErrnoError(32);
+ }
+ }
+ }
+ }
+
+ return { path: current_path, node: current };
+ },
+ getPath(node) {
+ var path;
+ while (true) {
+ if (FS.isRoot(node)) {
+ var mount = node.mount.mountpoint;
+ if (!path) return mount;
+ return mount[mount.length-1] !== '/' ? `${mount}/${path}` : mount + path;
+ }
+ path = path ? `${node.name}/${path}` : node.name;
+ node = node.parent;
+ }
+ },
+ hashName(parentid, name) {
+ var hash = 0;
+
+ for (var i = 0; i < name.length; i++) {
+ hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+ }
+ return ((parentid + hash) >>> 0) % FS.nameTable.length;
+ },
+ hashAddNode(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ node.name_next = FS.nameTable[hash];
+ FS.nameTable[hash] = node;
+ },
+ hashRemoveNode(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ if (FS.nameTable[hash] === node) {
+ FS.nameTable[hash] = node.name_next;
+ } else {
+ var current = FS.nameTable[hash];
+ while (current) {
+ if (current.name_next === node) {
+ current.name_next = node.name_next;
+ break;
+ }
+ current = current.name_next;
+ }
+ }
+ },
+ lookupNode(parent, name) {
+ var errCode = FS.mayLookup(parent);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ var hash = FS.hashName(parent.id, name);
+ for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+ var nodeName = node.name;
+ if (node.parent.id === parent.id && nodeName === name) {
+ return node;
+ }
+ }
+ // if we failed to find it in the cache, call into the VFS
+ return FS.lookup(parent, name);
+ },
+ createNode(parent, name, mode, rdev) {
+ var node = new FS.FSNode(parent, name, mode, rdev);
+
+ FS.hashAddNode(node);
+
+ return node;
+ },
+ destroyNode(node) {
+ FS.hashRemoveNode(node);
+ },
+ isRoot(node) {
+ return node === node.parent;
+ },
+ isMountpoint(node) {
+ return !!node.mounted;
+ },
+ isFile(mode) {
+ return (mode & 61440) === 32768;
+ },
+ isDir(mode) {
+ return (mode & 61440) === 16384;
+ },
+ isLink(mode) {
+ return (mode & 61440) === 40960;
+ },
+ isChrdev(mode) {
+ return (mode & 61440) === 8192;
+ },
+ isBlkdev(mode) {
+ return (mode & 61440) === 24576;
+ },
+ isFIFO(mode) {
+ return (mode & 61440) === 4096;
+ },
+ isSocket(mode) {
+ return (mode & 49152) === 49152;
+ },
+ flagsToPermissionString(flag) {
+ var perms = ['r', 'w', 'rw'][flag & 3];
+ if ((flag & 512)) {
+ perms += 'w';
+ }
+ return perms;
+ },
+ nodePermissions(node, perms) {
+ if (FS.ignorePermissions) {
+ return 0;
+ }
+ // return 0 if any user, group or owner bits are set.
+ if (perms.includes('r') && !(node.mode & 292)) {
+ return 2;
+ } else if (perms.includes('w') && !(node.mode & 146)) {
+ return 2;
+ } else if (perms.includes('x') && !(node.mode & 73)) {
+ return 2;
+ }
+ return 0;
+ },
+ mayLookup(dir) {
+ if (!FS.isDir(dir.mode)) return 54;
+ var errCode = FS.nodePermissions(dir, 'x');
+ if (errCode) return errCode;
+ if (!dir.node_ops.lookup) return 2;
+ return 0;
+ },
+ mayCreate(dir, name) {
+ try {
+ var node = FS.lookupNode(dir, name);
+ return 20;
+ } catch (e) {
+ }
+ return FS.nodePermissions(dir, 'wx');
+ },
+ mayDelete(dir, name, isdir) {
+ var node;
+ try {
+ node = FS.lookupNode(dir, name);
+ } catch (e) {
+ return e.errno;
+ }
+ var errCode = FS.nodePermissions(dir, 'wx');
+ if (errCode) {
+ return errCode;
+ }
+ if (isdir) {
+ if (!FS.isDir(node.mode)) {
+ return 54;
+ }
+ if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+ return 10;
+ }
+ } else {
+ if (FS.isDir(node.mode)) {
+ return 31;
+ }
+ }
+ return 0;
+ },
+ mayOpen(node, flags) {
+ if (!node) {
+ return 44;
+ }
+ if (FS.isLink(node.mode)) {
+ return 32;
+ } else if (FS.isDir(node.mode)) {
+ if (FS.flagsToPermissionString(flags) !== 'r' || // opening for write
+ (flags & 512)) { // TODO: check for O_SEARCH? (== search for dir only)
+ return 31;
+ }
+ }
+ return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+ },
+ MAX_OPEN_FDS:4096,
+ nextfd() {
+ for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) {
+ if (!FS.streams[fd]) {
+ return fd;
+ }
+ }
+ throw new FS.ErrnoError(33);
+ },
+ getStreamChecked(fd) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(8);
+ }
+ return stream;
+ },
+ getStream:(fd) => FS.streams[fd],
+ createStream(stream, fd = -1) {
+
+ // clone it, so we can return an instance of FSStream
+ stream = Object.assign(new FS.FSStream(), stream);
+ if (fd == -1) {
+ fd = FS.nextfd();
+ }
+ stream.fd = fd;
+ FS.streams[fd] = stream;
+ return stream;
+ },
+ closeStream(fd) {
+ FS.streams[fd] = null;
+ },
+ dupStream(origStream, fd = -1) {
+ var stream = FS.createStream(origStream, fd);
+ stream.stream_ops?.dup?.(stream);
+ return stream;
+ },
+ chrdev_stream_ops:{
+ open(stream) {
+ var device = FS.getDevice(stream.node.rdev);
+ // override node's stream ops with the device's
+ stream.stream_ops = device.stream_ops;
+ // forward the open call
+ stream.stream_ops.open?.(stream);
+ },
+ llseek() {
+ throw new FS.ErrnoError(70);
+ },
+ },
+ major:(dev) => ((dev) >> 8),
+ minor:(dev) => ((dev) & 0xff),
+ makedev:(ma, mi) => ((ma) << 8 | (mi)),
+ registerDevice(dev, ops) {
+ FS.devices[dev] = { stream_ops: ops };
+ },
+ getDevice:(dev) => FS.devices[dev],
+ getMounts(mount) {
+ var mounts = [];
+ var check = [mount];
+
+ while (check.length) {
+ var m = check.pop();
+
+ mounts.push(m);
+
+ check.push(...m.mounts);
+ }
+
+ return mounts;
+ },
+ syncfs(populate, callback) {
+ if (typeof populate == 'function') {
+ callback = populate;
+ populate = false;
+ }
+
+ FS.syncFSRequests++;
+
+ if (FS.syncFSRequests > 1) {
+ err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);
+ }
+
+ var mounts = FS.getMounts(FS.root.mount);
+ var completed = 0;
+
+ function doCallback(errCode) {
+ FS.syncFSRequests--;
+ return callback(errCode);
+ }
+
+ function done(errCode) {
+ if (errCode) {
+ if (!done.errored) {
+ done.errored = true;
+ return doCallback(errCode);
+ }
+ return;
+ }
+ if (++completed >= mounts.length) {
+ doCallback(null);
+ }
+ };
+
+ // sync all mounts
+ mounts.forEach((mount) => {
+ if (!mount.type.syncfs) {
+ return done(null);
+ }
+ mount.type.syncfs(mount, populate, done);
+ });
+ },
+ mount(type, opts, mountpoint) {
+ var root = mountpoint === '/';
+ var pseudo = !mountpoint;
+ var node;
+
+ if (root && FS.root) {
+ throw new FS.ErrnoError(10);
+ } else if (!root && !pseudo) {
+ var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+ mountpoint = lookup.path; // use the absolute path
+ node = lookup.node;
+
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+
+ if (!FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ }
+
+ var mount = {
+ type,
+ opts,
+ mountpoint,
+ mounts: []
+ };
+
+ // create a root node for the fs
+ var mountRoot = type.mount(mount);
+ mountRoot.mount = mount;
+ mount.root = mountRoot;
+
+ if (root) {
+ FS.root = mountRoot;
+ } else if (node) {
+ // set as a mountpoint
+ node.mounted = mount;
+
+ // add the new mount to the current mount's children
+ if (node.mount) {
+ node.mount.mounts.push(mount);
+ }
+ }
+
+ return mountRoot;
+ },
+ unmount(mountpoint) {
+ var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+ if (!FS.isMountpoint(lookup.node)) {
+ throw new FS.ErrnoError(28);
+ }
+
+ // destroy the nodes for this mount, and all its child mounts
+ var node = lookup.node;
+ var mount = node.mounted;
+ var mounts = FS.getMounts(mount);
+
+ Object.keys(FS.nameTable).forEach((hash) => {
+ var current = FS.nameTable[hash];
+
+ while (current) {
+ var next = current.name_next;
+
+ if (mounts.includes(current.mount)) {
+ FS.destroyNode(current);
+ }
+
+ current = next;
+ }
+ });
+
+ // no longer a mountpoint
+ node.mounted = null;
+
+ // remove this mount from the child mounts
+ var idx = node.mount.mounts.indexOf(mount);
+ node.mount.mounts.splice(idx, 1);
+ },
+ lookup(parent, name) {
+ return parent.node_ops.lookup(parent, name);
+ },
+ mknod(path, mode, dev) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ if (!name || name === '.' || name === '..') {
+ throw new FS.ErrnoError(28);
+ }
+ var errCode = FS.mayCreate(parent, name);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.mknod) {
+ throw new FS.ErrnoError(63);
+ }
+ return parent.node_ops.mknod(parent, name, mode, dev);
+ },
+ create(path, mode) {
+ mode = mode !== undefined ? mode : 438 /* 0666 */;
+ mode &= 4095;
+ mode |= 32768;
+ return FS.mknod(path, mode, 0);
+ },
+ mkdir(path, mode) {
+ mode = mode !== undefined ? mode : 511 /* 0777 */;
+ mode &= 511 | 512;
+ mode |= 16384;
+ return FS.mknod(path, mode, 0);
+ },
+ mkdirTree(path, mode) {
+ var dirs = path.split('/');
+ var d = '';
+ for (var i = 0; i < dirs.length; ++i) {
+ if (!dirs[i]) continue;
+ d += '/' + dirs[i];
+ try {
+ FS.mkdir(d, mode);
+ } catch(e) {
+ if (e.errno != 20) throw e;
+ }
+ }
+ },
+ mkdev(path, mode, dev) {
+ if (typeof dev == 'undefined') {
+ dev = mode;
+ mode = 438 /* 0666 */;
+ }
+ mode |= 8192;
+ return FS.mknod(path, mode, dev);
+ },
+ symlink(oldpath, newpath) {
+ if (!PATH_FS.resolve(oldpath)) {
+ throw new FS.ErrnoError(44);
+ }
+ var lookup = FS.lookupPath(newpath, { parent: true });
+ var parent = lookup.node;
+ if (!parent) {
+ throw new FS.ErrnoError(44);
+ }
+ var newname = PATH.basename(newpath);
+ var errCode = FS.mayCreate(parent, newname);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.symlink) {
+ throw new FS.ErrnoError(63);
+ }
+ return parent.node_ops.symlink(parent, newname, oldpath);
+ },
+ rename(old_path, new_path) {
+ var old_dirname = PATH.dirname(old_path);
+ var new_dirname = PATH.dirname(new_path);
+ var old_name = PATH.basename(old_path);
+ var new_name = PATH.basename(new_path);
+ // parents must exist
+ var lookup, old_dir, new_dir;
+
+ // let the errors from non existent directories percolate up
+ lookup = FS.lookupPath(old_path, { parent: true });
+ old_dir = lookup.node;
+ lookup = FS.lookupPath(new_path, { parent: true });
+ new_dir = lookup.node;
+
+ if (!old_dir || !new_dir) throw new FS.ErrnoError(44);
+ // need to be part of the same mount
+ if (old_dir.mount !== new_dir.mount) {
+ throw new FS.ErrnoError(75);
+ }
+ // source must exist
+ var old_node = FS.lookupNode(old_dir, old_name);
+ // old path should not be an ancestor of the new path
+ var relative = PATH_FS.relative(old_path, new_dirname);
+ if (relative.charAt(0) !== '.') {
+ throw new FS.ErrnoError(28);
+ }
+ // new path should not be an ancestor of the old path
+ relative = PATH_FS.relative(new_path, old_dirname);
+ if (relative.charAt(0) !== '.') {
+ throw new FS.ErrnoError(55);
+ }
+ // see if the new path already exists
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {
+ // not fatal
+ }
+ // early out if nothing needs to change
+ if (old_node === new_node) {
+ return;
+ }
+ // we'll need to delete the old entry
+ var isdir = FS.isDir(old_node.mode);
+ var errCode = FS.mayDelete(old_dir, old_name, isdir);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ // need delete permissions if we'll be overwriting.
+ // need create permissions if new doesn't already exist.
+ errCode = new_node ?
+ FS.mayDelete(new_dir, new_name, isdir) :
+ FS.mayCreate(new_dir, new_name);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!old_dir.node_ops.rename) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+ throw new FS.ErrnoError(10);
+ }
+ // if we are going to change the parent, check write permissions
+ if (new_dir !== old_dir) {
+ errCode = FS.nodePermissions(old_dir, 'w');
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ }
+ // remove the node from the lookup hash
+ FS.hashRemoveNode(old_node);
+ // do the underlying fs rename
+ try {
+ old_dir.node_ops.rename(old_node, new_dir, new_name);
+ // update old node (we do this here to avoid each backend
+ // needing to)
+ old_node.parent = new_dir;
+ } catch (e) {
+ throw e;
+ } finally {
+ // add the node back to the hash (in case node_ops.rename
+ // changed its name)
+ FS.hashAddNode(old_node);
+ }
+ },
+ rmdir(path) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var errCode = FS.mayDelete(parent, name, true);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.rmdir) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ parent.node_ops.rmdir(parent, name);
+ FS.destroyNode(node);
+ },
+ readdir(path) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ var node = lookup.node;
+ if (!node.node_ops.readdir) {
+ throw new FS.ErrnoError(54);
+ }
+ return node.node_ops.readdir(node);
+ },
+ unlink(path) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ if (!parent) {
+ throw new FS.ErrnoError(44);
+ }
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var errCode = FS.mayDelete(parent, name, false);
+ if (errCode) {
+ // According to POSIX, we should map EISDIR to EPERM, but
+ // we instead do what Linux does (and we must, as we use
+ // the musl linux libc).
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.unlink) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ parent.node_ops.unlink(parent, name);
+ FS.destroyNode(node);
+ },
+ readlink(path) {
+ var lookup = FS.lookupPath(path);
+ var link = lookup.node;
+ if (!link) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!link.node_ops.readlink) {
+ throw new FS.ErrnoError(28);
+ }
+ return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link));
+ },
+ stat(path, dontFollow) {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ var node = lookup.node;
+ if (!node) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!node.node_ops.getattr) {
+ throw new FS.ErrnoError(63);
+ }
+ return node.node_ops.getattr(node);
+ },
+ lstat(path) {
+ return FS.stat(path, true);
+ },
+ chmod(path, mode, dontFollow) {
+ var node;
+ if (typeof path == 'string') {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ node.node_ops.setattr(node, {
+ mode: (mode & 4095) | (node.mode & ~4095),
+ timestamp: Date.now()
+ });
+ },
+ lchmod(path, mode) {
+ FS.chmod(path, mode, true);
+ },
+ fchmod(fd, mode) {
+ var stream = FS.getStreamChecked(fd);
+ FS.chmod(stream.node, mode);
+ },
+ chown(path, uid, gid, dontFollow) {
+ var node;
+ if (typeof path == 'string') {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ node.node_ops.setattr(node, {
+ timestamp: Date.now()
+ // we ignore the uid / gid for now
+ });
+ },
+ lchown(path, uid, gid) {
+ FS.chown(path, uid, gid, true);
+ },
+ fchown(fd, uid, gid) {
+ var stream = FS.getStreamChecked(fd);
+ FS.chown(stream.node, uid, gid);
+ },
+ truncate(path, len) {
+ if (len < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ var node;
+ if (typeof path == 'string') {
+ var lookup = FS.lookupPath(path, { follow: true });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!FS.isFile(node.mode)) {
+ throw new FS.ErrnoError(28);
+ }
+ var errCode = FS.nodePermissions(node, 'w');
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ node.node_ops.setattr(node, {
+ size: len,
+ timestamp: Date.now()
+ });
+ },
+ ftruncate(fd, len) {
+ var stream = FS.getStreamChecked(fd);
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(28);
+ }
+ FS.truncate(stream.node, len);
+ },
+ utime(path, atime, mtime) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ var node = lookup.node;
+ node.node_ops.setattr(node, {
+ timestamp: Math.max(atime, mtime)
+ });
+ },
+ open(path, flags, mode) {
+ if (path === "") {
+ throw new FS.ErrnoError(44);
+ }
+ flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags;
+ if ((flags & 64)) {
+ mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode;
+ mode = (mode & 4095) | 32768;
+ } else {
+ mode = 0;
+ }
+ var node;
+ if (typeof path == 'object') {
+ node = path;
+ } else {
+ path = PATH.normalize(path);
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & 131072)
+ });
+ node = lookup.node;
+ } catch (e) {
+ // ignore
+ }
+ }
+ // perhaps we need to create the node
+ var created = false;
+ if ((flags & 64)) {
+ if (node) {
+ // if O_CREAT and O_EXCL are set, error out if the node already exists
+ if ((flags & 128)) {
+ throw new FS.ErrnoError(20);
+ }
+ } else {
+ // node doesn't exist, try to create it
+ node = FS.mknod(path, mode, 0);
+ created = true;
+ }
+ }
+ if (!node) {
+ throw new FS.ErrnoError(44);
+ }
+ // can't truncate a device
+ if (FS.isChrdev(node.mode)) {
+ flags &= ~512;
+ }
+ // if asked only for a directory, then this must be one
+ if ((flags & 65536) && !FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ // check permissions, if this is not a file we just created now (it is ok to
+ // create and write to a file with read-only permissions; it is read-only
+ // for later use)
+ if (!created) {
+ var errCode = FS.mayOpen(node, flags);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ }
+ // do truncation if necessary
+ if ((flags & 512) && !created) {
+ FS.truncate(node, 0);
+ }
+ // we've already handled these, don't pass down to the underlying vfs
+ flags &= ~(128 | 512 | 131072);
+
+ // register the stream with the filesystem
+ var stream = FS.createStream({
+ node,
+ path: FS.getPath(node), // we want the absolute path to the node
+ flags,
+ seekable: true,
+ position: 0,
+ stream_ops: node.stream_ops,
+ // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+ ungotten: [],
+ error: false
+ });
+ // call the new stream's open function
+ if (stream.stream_ops.open) {
+ stream.stream_ops.open(stream);
+ }
+ if (Module['logReadFiles'] && !(flags & 1)) {
+ if (!(path in FS.readFiles)) {
+ FS.readFiles[path] = 1;
+ }
+ }
+ return stream;
+ },
+ close(stream) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (stream.getdents) stream.getdents = null; // free readdir state
+ try {
+ if (stream.stream_ops.close) {
+ stream.stream_ops.close(stream);
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ FS.closeStream(stream.fd);
+ }
+ stream.fd = null;
+ },
+ isClosed(stream) {
+ return stream.fd === null;
+ },
+ llseek(stream, offset, whence) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (!stream.seekable || !stream.stream_ops.llseek) {
+ throw new FS.ErrnoError(70);
+ }
+ if (whence != 0 && whence != 1 && whence != 2) {
+ throw new FS.ErrnoError(28);
+ }
+ stream.position = stream.stream_ops.llseek(stream, offset, whence);
+ stream.ungotten = [];
+ return stream.position;
+ },
+ read(stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if ((stream.flags & 2097155) === 1) {
+ throw new FS.ErrnoError(8);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!stream.stream_ops.read) {
+ throw new FS.ErrnoError(28);
+ }
+ var seeking = typeof position != 'undefined';
+ if (!seeking) {
+ position = stream.position;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(70);
+ }
+ var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesRead;
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, position, canOwn) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(8);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!stream.stream_ops.write) {
+ throw new FS.ErrnoError(28);
+ }
+ if (stream.seekable && stream.flags & 1024) {
+ // seek to the end before writing in append mode
+ FS.llseek(stream, 0, 2);
+ }
+ var seeking = typeof position != 'undefined';
+ if (!seeking) {
+ position = stream.position;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(70);
+ }
+ var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+ if (!seeking) stream.position += bytesWritten;
+ return bytesWritten;
+ },
+ allocate(stream, offset, length) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (offset < 0 || length <= 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(8);
+ }
+ if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ if (!stream.stream_ops.allocate) {
+ throw new FS.ErrnoError(138);
+ }
+ stream.stream_ops.allocate(stream, offset, length);
+ },
+ mmap(stream, length, position, prot, flags) {
+ // User requests writing to file (prot & PROT_WRITE != 0).
+ // Checking if we have permissions to write to the file unless
+ // MAP_PRIVATE flag is set. According to POSIX spec it is possible
+ // to write to file opened in read-only mode with MAP_PRIVATE flag,
+ // as all modifications will be visible only in the memory of
+ // the current process.
+ if ((prot & 2) !== 0
+ && (flags & 2) === 0
+ && (stream.flags & 2097155) !== 2) {
+ throw new FS.ErrnoError(2);
+ }
+ if ((stream.flags & 2097155) === 1) {
+ throw new FS.ErrnoError(2);
+ }
+ if (!stream.stream_ops.mmap) {
+ throw new FS.ErrnoError(43);
+ }
+ if (!length) {
+ throw new FS.ErrnoError(28);
+ }
+ return stream.stream_ops.mmap(stream, length, position, prot, flags);
+ },
+ msync(stream, buffer, offset, length, mmapFlags) {
+ if (!stream.stream_ops.msync) {
+ return 0;
+ }
+ return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);
+ },
+ ioctl(stream, cmd, arg) {
+ if (!stream.stream_ops.ioctl) {
+ throw new FS.ErrnoError(59);
+ }
+ return stream.stream_ops.ioctl(stream, cmd, arg);
+ },
+ readFile(path, opts = {}) {
+ opts.flags = opts.flags || 0;
+ opts.encoding = opts.encoding || 'binary';
+ if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+ throw new Error(`Invalid encoding type "${opts.encoding}"`);
+ }
+ var ret;
+ var stream = FS.open(path, opts.flags);
+ var stat = FS.stat(path);
+ var length = stat.size;
+ var buf = new Uint8Array(length);
+ FS.read(stream, buf, 0, length, 0);
+ if (opts.encoding === 'utf8') {
+ ret = UTF8ArrayToString(buf);
+ } else if (opts.encoding === 'binary') {
+ ret = buf;
+ }
+ FS.close(stream);
+ return ret;
+ },
+ writeFile(path, data, opts = {}) {
+ opts.flags = opts.flags || 577;
+ var stream = FS.open(path, opts.flags, opts.mode);
+ if (typeof data == 'string') {
+ var buf = new Uint8Array(lengthBytesUTF8(data)+1);
+ var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);
+ FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn);
+ } else if (ArrayBuffer.isView(data)) {
+ FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
+ } else {
+ throw new Error('Unsupported data type');
+ }
+ FS.close(stream);
+ },
+ cwd:() => FS.currentPath,
+ chdir(path) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ if (lookup.node === null) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!FS.isDir(lookup.node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ var errCode = FS.nodePermissions(lookup.node, 'x');
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ FS.currentPath = lookup.path;
+ },
+ createDefaultDirectories() {
+ FS.mkdir('/tmp');
+ FS.mkdir('/home');
+ FS.mkdir('/home/web_user');
+ },
+ createDefaultDevices() {
+ // create /dev
+ FS.mkdir('/dev');
+ // setup /dev/null
+ FS.registerDevice(FS.makedev(1, 3), {
+ read: () => 0,
+ write: (stream, buffer, offset, length, pos) => length,
+ });
+ FS.mkdev('/dev/null', FS.makedev(1, 3));
+ // setup /dev/tty and /dev/tty1
+ // stderr needs to print output using err() rather than out()
+ // so we register a second tty just for it.
+ TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+ TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+ FS.mkdev('/dev/tty', FS.makedev(5, 0));
+ FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+ // setup /dev/[u]random
+ // use a buffer to avoid overhead of individual crypto calls per byte
+ var randomBuffer = new Uint8Array(1024), randomLeft = 0;
+ var randomByte = () => {
+ if (randomLeft === 0) {
+ randomLeft = randomFill(randomBuffer).byteLength;
+ }
+ return randomBuffer[--randomLeft];
+ };
+ FS.createDevice('/dev', 'random', randomByte);
+ FS.createDevice('/dev', 'urandom', randomByte);
+ // we're not going to emulate the actual shm device,
+ // just create the tmp dirs that reside in it commonly
+ FS.mkdir('/dev/shm');
+ FS.mkdir('/dev/shm/tmp');
+ },
+ createSpecialDirectories() {
+ // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the
+ // name of the stream for fd 6 (see test_unistd_ttyname)
+ FS.mkdir('/proc');
+ var proc_self = FS.mkdir('/proc/self');
+ FS.mkdir('/proc/self/fd');
+ FS.mount({
+ mount() {
+ var node = FS.createNode(proc_self, 'fd', 16384 | 511 /* 0777 */, 73);
+ node.node_ops = {
+ lookup(parent, name) {
+ var fd = +name;
+ var stream = FS.getStreamChecked(fd);
+ var ret = {
+ parent: null,
+ mount: { mountpoint: 'fake' },
+ node_ops: { readlink: () => stream.path },
+ };
+ ret.parent = ret; // make it look like a simple root node
+ return ret;
+ }
+ };
+ return node;
+ }
+ }, {}, '/proc/self/fd');
+ },
+ createStandardStreams(input, output, error) {
+ // TODO deprecate the old functionality of a single
+ // input / output callback and that utilizes FS.createDevice
+ // and instead require a unique set of stream ops
+
+ // by default, we symlink the standard streams to the
+ // default tty devices. however, if the standard streams
+ // have been overwritten we create a unique device for
+ // them instead.
+ if (input) {
+ FS.createDevice('/dev', 'stdin', input);
+ } else {
+ FS.symlink('/dev/tty', '/dev/stdin');
+ }
+ if (output) {
+ FS.createDevice('/dev', 'stdout', null, output);
+ } else {
+ FS.symlink('/dev/tty', '/dev/stdout');
+ }
+ if (error) {
+ FS.createDevice('/dev', 'stderr', null, error);
+ } else {
+ FS.symlink('/dev/tty1', '/dev/stderr');
+ }
+
+ // open default streams for the stdin, stdout and stderr devices
+ var stdin = FS.open('/dev/stdin', 0);
+ var stdout = FS.open('/dev/stdout', 1);
+ var stderr = FS.open('/dev/stderr', 1);
+ },
+ staticInit() {
+ // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+ [44].forEach((code) => {
+ FS.genericErrors[code] = new FS.ErrnoError(code);
+ FS.genericErrors[code].stack = '<generic error, no stack>';
+ });
+
+ FS.nameTable = new Array(4096);
+
+ FS.mount(MEMFS, {}, '/');
+
+ FS.createDefaultDirectories();
+ FS.createDefaultDevices();
+ FS.createSpecialDirectories();
+
+ FS.filesystems = {
+ 'MEMFS': MEMFS,
+ };
+ },
+ init(input, output, error) {
+ FS.initialized = true;
+
+ // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+ input ??= Module['stdin'];
+ output ??= Module['stdout'];
+ error ??= Module['stderr'];
+
+ FS.createStandardStreams(input, output, error);
+ },
+ quit() {
+ FS.initialized = false;
+ // force-flush all streams, so we get musl std streams printed out
+ // close all of our streams
+ for (var i = 0; i < FS.streams.length; i++) {
+ var stream = FS.streams[i];
+ if (!stream) {
+ continue;
+ }
+ FS.close(stream);
+ }
+ },
+ findObject(path, dontResolveLastLink) {
+ var ret = FS.analyzePath(path, dontResolveLastLink);
+ if (!ret.exists) {
+ return null;
+ }
+ return ret.object;
+ },
+ analyzePath(path, dontResolveLastLink) {
+ // operate from within the context of the symlink's target
+ try {
+ var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+ path = lookup.path;
+ } catch (e) {
+ }
+ var ret = {
+ isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+ parentExists: false, parentPath: null, parentObject: null
+ };
+ try {
+ var lookup = FS.lookupPath(path, { parent: true });
+ ret.parentExists = true;
+ ret.parentPath = lookup.path;
+ ret.parentObject = lookup.node;
+ ret.name = PATH.basename(path);
+ lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+ ret.exists = true;
+ ret.path = lookup.path;
+ ret.object = lookup.node;
+ ret.name = lookup.node.name;
+ ret.isRoot = lookup.path === '/';
+ } catch (e) {
+ ret.error = e.errno;
+ };
+ return ret;
+ },
+ createPath(parent, path, canRead, canWrite) {
+ parent = typeof parent == 'string' ? parent : FS.getPath(parent);
+ var parts = path.split('/').reverse();
+ while (parts.length) {
+ var part = parts.pop();
+ if (!part) continue;
+ var current = PATH.join2(parent, part);
+ try {
+ FS.mkdir(current);
+ } catch (e) {
+ // ignore EEXIST
+ }
+ parent = current;
+ }
+ return current;
+ },
+ createFile(parent, name, properties, canRead, canWrite) {
+ var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name);
+ var mode = FS_getMode(canRead, canWrite);
+ return FS.create(path, mode);
+ },
+ createDataFile(parent, name, data, canRead, canWrite, canOwn) {
+ var path = name;
+ if (parent) {
+ parent = typeof parent == 'string' ? parent : FS.getPath(parent);
+ path = name ? PATH.join2(parent, name) : parent;
+ }
+ var mode = FS_getMode(canRead, canWrite);
+ var node = FS.create(path, mode);
+ if (data) {
+ if (typeof data == 'string') {
+ var arr = new Array(data.length);
+ for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+ data = arr;
+ }
+ // make sure we can write to the file
+ FS.chmod(node, mode | 146);
+ var stream = FS.open(node, 577);
+ FS.write(stream, data, 0, data.length, 0, canOwn);
+ FS.close(stream);
+ FS.chmod(node, mode);
+ }
+ },
+ createDevice(parent, name, input, output) {
+ var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name);
+ var mode = FS_getMode(!!input, !!output);
+ FS.createDevice.major ??= 64;
+ var dev = FS.makedev(FS.createDevice.major++, 0);
+ // Create a fake device that a set of stream ops to emulate
+ // the old behavior.
+ FS.registerDevice(dev, {
+ open(stream) {
+ stream.seekable = false;
+ },
+ close(stream) {
+ // flush any pending line data
+ if (output?.buffer?.length) {
+ output(10);
+ }
+ },
+ read(stream, buffer, offset, length, pos /* ignored */) {
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = input();
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(6);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset+i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, pos) {
+ for (var i = 0; i < length; i++) {
+ try {
+ output(buffer[offset+i]);
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ });
+ return FS.mkdev(path, mode, dev);
+ },
+ forceLoadFile(obj) {
+ if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+ if (typeof XMLHttpRequest != 'undefined') {
+ throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+ } else { // Command-line.
+ try {
+ obj.contents = readBinary(obj.url);
+ obj.usedBytes = obj.contents.length;
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ }
+ },
+ createLazyFile(parent, name, url, canRead, canWrite) {
+ // Lazy chunked Uint8Array (implements get and length from Uint8Array).
+ // Actual getting is abstracted away for eventual reuse.
+ class LazyUint8Array {
+ lengthKnown = false;
+ chunks = []; // Loaded chunks. Index is the chunk number
+ get(idx) {
+ if (idx > this.length-1 || idx < 0) {
+ return undefined;
+ }
+ var chunkOffset = idx % this.chunkSize;
+ var chunkNum = (idx / this.chunkSize)|0;
+ return this.getter(chunkNum)[chunkOffset];
+ }
+ setDataGetter(getter) {
+ this.getter = getter;
+ }
+ cacheLength() {
+ // Find length
+ var xhr = new XMLHttpRequest();
+ xhr.open('HEAD', url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+ var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
+
+ var chunkSize = 1024*1024; // Chunk size in bytes
+
+ if (!hasByteServing) chunkSize = datalength;
+
+ // Function to get a range from the remote URL.
+ var doXHR = (from, to) => {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+ // Some hints to the browser that we want binary data.
+ xhr.responseType = 'arraybuffer';
+ if (xhr.overrideMimeType) {
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ if (xhr.response !== undefined) {
+ return new Uint8Array(/** @type{Array<number>} */(xhr.response || []));
+ }
+ return intArrayFromString(xhr.responseText || '', true);
+ };
+ var lazyArray = this;
+ lazyArray.setDataGetter((chunkNum) => {
+ var start = chunkNum * chunkSize;
+ var end = (chunkNum+1) * chunkSize - 1; // including this byte
+ end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+ if (typeof lazyArray.chunks[chunkNum] == 'undefined') {
+ lazyArray.chunks[chunkNum] = doXHR(start, end);
+ }
+ if (typeof lazyArray.chunks[chunkNum] == 'undefined') throw new Error('doXHR failed!');
+ return lazyArray.chunks[chunkNum];
+ });
+
+ if (usesGzip || !datalength) {
+ // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length
+ chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file
+ datalength = this.getter(0).length;
+ chunkSize = datalength;
+ out("LazyFiles on gzip forces download of the whole file when length is accessed");
+ }
+
+ this._length = datalength;
+ this._chunkSize = chunkSize;
+ this.lengthKnown = true;
+ }
+ get length() {
+ if (!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._length;
+ }
+ get chunkSize() {
+ if (!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._chunkSize;
+ }
+ }
+
+ if (typeof XMLHttpRequest != 'undefined') {
+ if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+ var lazyArray = new LazyUint8Array();
+ var properties = { isDevice: false, contents: lazyArray };
+ } else {
+ var properties = { isDevice: false, url: url };
+ }
+
+ var node = FS.createFile(parent, name, properties, canRead, canWrite);
+ // This is a total hack, but I want to get this lazy file code out of the
+ // core of MEMFS. If we want to keep this lazy file concept I feel it should
+ // be its own thin LAZYFS proxying calls to MEMFS.
+ if (properties.contents) {
+ node.contents = properties.contents;
+ } else if (properties.url) {
+ node.contents = null;
+ node.url = properties.url;
+ }
+ // Add a function that defers querying the file size until it is asked the first time.
+ Object.defineProperties(node, {
+ usedBytes: {
+ get: function() { return this.contents.length; }
+ }
+ });
+ // override each stream op with one that tries to force load the lazy file first
+ var stream_ops = {};
+ var keys = Object.keys(node.stream_ops);
+ keys.forEach((key) => {
+ var fn = node.stream_ops[key];
+ stream_ops[key] = (...args) => {
+ FS.forceLoadFile(node);
+ return fn(...args);
+ };
+ });
+ function writeChunks(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ if (position >= contents.length)
+ return 0;
+ var size = Math.min(contents.length - position, length);
+ if (contents.slice) { // normal array
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ } else {
+ for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+ buffer[offset + i] = contents.get(position + i);
+ }
+ }
+ return size;
+ }
+ // use a custom read function
+ stream_ops.read = (stream, buffer, offset, length, position) => {
+ FS.forceLoadFile(node);
+ return writeChunks(stream, buffer, offset, length, position)
+ };
+ // use a custom mmap function
+ stream_ops.mmap = (stream, length, position, prot, flags) => {
+ FS.forceLoadFile(node);
+ var ptr = mmapAlloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(48);
+ }
+ writeChunks(stream, HEAP8, ptr, length, position);
+ return { ptr, allocated: true };
+ };
+ node.stream_ops = stream_ops;
+ return node;
+ },
+ };
+
+ var SYSCALLS = {
+ DEFAULT_POLLMASK:5,
+ calculateAt(dirfd, path, allowEmpty) {
+ if (PATH.isAbs(path)) {
+ return path;
+ }
+ // relative path
+ var dir;
+ if (dirfd === -100) {
+ dir = FS.cwd();
+ } else {
+ var dirstream = SYSCALLS.getStreamFromFD(dirfd);
+ dir = dirstream.path;
+ }
+ if (path.length == 0) {
+ if (!allowEmpty) {
+ throw new FS.ErrnoError(44);;
+ }
+ return dir;
+ }
+ return PATH.join2(dir, path);
+ },
+ doStat(func, path, buf) {
+ var stat = func(path);
+ HEAP32[((buf)>>2)] = stat.dev;
+ HEAP32[(((buf)+(4))>>2)] = stat.mode;
+ HEAPU32[(((buf)+(8))>>2)] = stat.nlink;
+ HEAP32[(((buf)+(12))>>2)] = stat.uid;
+ HEAP32[(((buf)+(16))>>2)] = stat.gid;
+ HEAP32[(((buf)+(20))>>2)] = stat.rdev;
+ HEAP64[(((buf)+(24))>>3)] = BigInt(stat.size);
+ HEAP32[(((buf)+(32))>>2)] = 4096;
+ HEAP32[(((buf)+(36))>>2)] = stat.blocks;
+ var atime = stat.atime.getTime();
+ var mtime = stat.mtime.getTime();
+ var ctime = stat.ctime.getTime();
+ HEAP64[(((buf)+(40))>>3)] = BigInt(Math.floor(atime / 1000));
+ HEAPU32[(((buf)+(48))>>2)] = (atime % 1000) * 1000 * 1000;
+ HEAP64[(((buf)+(56))>>3)] = BigInt(Math.floor(mtime / 1000));
+ HEAPU32[(((buf)+(64))>>2)] = (mtime % 1000) * 1000 * 1000;
+ HEAP64[(((buf)+(72))>>3)] = BigInt(Math.floor(ctime / 1000));
+ HEAPU32[(((buf)+(80))>>2)] = (ctime % 1000) * 1000 * 1000;
+ HEAP64[(((buf)+(88))>>3)] = BigInt(stat.ino);
+ return 0;
+ },
+ doMsync(addr, stream, len, flags, offset) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ if (flags & 2) {
+ // MAP_PRIVATE calls need not to be synced back to underlying fs
+ return 0;
+ }
+ var buffer = HEAPU8.slice(addr, addr + len);
+ FS.msync(stream, buffer, offset, len, flags);
+ },
+ getStreamFromFD(fd) {
+ var stream = FS.getStreamChecked(fd);
+ return stream;
+ },
+ varargs:undefined,
+ getStr(ptr) {
+ var ret = UTF8ToString(ptr);
+ return ret;
+ },
+ };
+ function ___syscall_chmod(path, mode) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ FS.chmod(path, mode);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_faccessat(dirfd, path, amode, flags) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ if (amode & ~7) {
+ // need a valid mode
+ return -28;
+ }
+ var lookup = FS.lookupPath(path, { follow: true });
+ var node = lookup.node;
+ if (!node) {
+ return -44;
+ }
+ var perms = '';
+ if (amode & 4) perms += 'r';
+ if (amode & 2) perms += 'w';
+ if (amode & 1) perms += 'x';
+ if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) {
+ return -2;
+ }
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_fchmod(fd, mode) {
+ try {
+
+ FS.fchmod(fd, mode);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_fchown32(fd, owner, group) {
+ try {
+
+ FS.fchown(fd, owner, group);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ /** @suppress {duplicate } */
+ var syscallGetVarargI = () => {
+ // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number.
+ var ret = HEAP32[((+SYSCALLS.varargs)>>2)];
+ SYSCALLS.varargs += 4;
+ return ret;
+ };
+ var syscallGetVarargP = syscallGetVarargI;
+
+
+ function ___syscall_fcntl64(fd, cmd, varargs) {
+ SYSCALLS.varargs = varargs;
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ switch (cmd) {
+ case 0: {
+ var arg = syscallGetVarargI();
+ if (arg < 0) {
+ return -28;
+ }
+ while (FS.streams[arg]) {
+ arg++;
+ }
+ var newStream;
+ newStream = FS.dupStream(stream, arg);
+ return newStream.fd;
+ }
+ case 1:
+ case 2:
+ return 0; // FD_CLOEXEC makes no sense for a single process.
+ case 3:
+ return stream.flags;
+ case 4: {
+ var arg = syscallGetVarargI();
+ stream.flags |= arg;
+ return 0;
+ }
+ case 12: {
+ var arg = syscallGetVarargP();
+ var offset = 0;
+ // We're always unlocked.
+ HEAP16[(((arg)+(offset))>>1)] = 2;
+ return 0;
+ }
+ case 13:
+ case 14:
+ return 0; // Pretend that the locking is successful.
+ }
+ return -28;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_fstat64(fd, buf) {
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ return SYSCALLS.doStat(FS.stat, stream.path, buf);
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ var INT53_MAX = 9007199254740992;
+
+ var INT53_MIN = -9007199254740992;
+ var bigintToI53Checked = (num) => (num < INT53_MIN || num > INT53_MAX) ? NaN : Number(num);
+ function ___syscall_ftruncate64(fd, length) {
+ length = bigintToI53Checked(length);
+
+
+ try {
+
+ if (isNaN(length)) return 61;
+ FS.ftruncate(fd, length);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ ;
+ }
+
+
+ var stringToUTF8 = (str, outPtr, maxBytesToWrite) => {
+ return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
+ };
+ function ___syscall_getcwd(buf, size) {
+ try {
+
+ if (size === 0) return -28;
+ var cwd = FS.cwd();
+ var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1;
+ if (size < cwdLengthInBytes) return -68;
+ stringToUTF8(cwd, buf, size);
+ return cwdLengthInBytes;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+
+ function ___syscall_ioctl(fd, op, varargs) {
+ SYSCALLS.varargs = varargs;
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ switch (op) {
+ case 21509: {
+ if (!stream.tty) return -59;
+ return 0;
+ }
+ case 21505: {
+ if (!stream.tty) return -59;
+ if (stream.tty.ops.ioctl_tcgets) {
+ var termios = stream.tty.ops.ioctl_tcgets(stream);
+ var argp = syscallGetVarargP();
+ HEAP32[((argp)>>2)] = termios.c_iflag || 0;
+ HEAP32[(((argp)+(4))>>2)] = termios.c_oflag || 0;
+ HEAP32[(((argp)+(8))>>2)] = termios.c_cflag || 0;
+ HEAP32[(((argp)+(12))>>2)] = termios.c_lflag || 0;
+ for (var i = 0; i < 32; i++) {
+ HEAP8[(argp + i)+(17)] = termios.c_cc[i] || 0;
+ }
+ return 0;
+ }
+ return 0;
+ }
+ case 21510:
+ case 21511:
+ case 21512: {
+ if (!stream.tty) return -59;
+ return 0; // no-op, not actually adjusting terminal settings
+ }
+ case 21506:
+ case 21507:
+ case 21508: {
+ if (!stream.tty) return -59;
+ if (stream.tty.ops.ioctl_tcsets) {
+ var argp = syscallGetVarargP();
+ var c_iflag = HEAP32[((argp)>>2)];
+ var c_oflag = HEAP32[(((argp)+(4))>>2)];
+ var c_cflag = HEAP32[(((argp)+(8))>>2)];
+ var c_lflag = HEAP32[(((argp)+(12))>>2)];
+ var c_cc = []
+ for (var i = 0; i < 32; i++) {
+ c_cc.push(HEAP8[(argp + i)+(17)]);
+ }
+ return stream.tty.ops.ioctl_tcsets(stream.tty, op, { c_iflag, c_oflag, c_cflag, c_lflag, c_cc });
+ }
+ return 0; // no-op, not actually adjusting terminal settings
+ }
+ case 21519: {
+ if (!stream.tty) return -59;
+ var argp = syscallGetVarargP();
+ HEAP32[((argp)>>2)] = 0;
+ return 0;
+ }
+ case 21520: {
+ if (!stream.tty) return -59;
+ return -28; // not supported
+ }
+ case 21531: {
+ var argp = syscallGetVarargP();
+ return FS.ioctl(stream, op, argp);
+ }
+ case 21523: {
+ // TODO: in theory we should write to the winsize struct that gets
+ // passed in, but for now musl doesn't read anything on it
+ if (!stream.tty) return -59;
+ if (stream.tty.ops.ioctl_tiocgwinsz) {
+ var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
+ var argp = syscallGetVarargP();
+ HEAP16[((argp)>>1)] = winsize[0];
+ HEAP16[(((argp)+(2))>>1)] = winsize[1];
+ }
+ return 0;
+ }
+ case 21524: {
+ // TODO: technically, this ioctl call should change the window size.
+ // but, since emscripten doesn't have any concept of a terminal window
+ // yet, we'll just silently throw it away as we do TIOCGWINSZ
+ if (!stream.tty) return -59;
+ return 0;
+ }
+ case 21515: {
+ if (!stream.tty) return -59;
+ return 0;
+ }
+ default: return -28; // not supported
+ }
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_lstat64(path, buf) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ return SYSCALLS.doStat(FS.lstat, path, buf);
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_mkdirat(dirfd, path, mode) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ // remove a trailing slash, if one - /a/b/ has basename of '', but
+ // we want to create b in the context of this function
+ path = PATH.normalize(path);
+ if (path[path.length-1] === '/') path = path.substr(0, path.length-1);
+ FS.mkdir(path, mode, 0);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_newfstatat(dirfd, path, buf, flags) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ var nofollow = flags & 256;
+ var allowEmpty = flags & 4096;
+ flags = flags & (~6400);
+ path = SYSCALLS.calculateAt(dirfd, path, allowEmpty);
+ return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf);
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+
+ function ___syscall_openat(dirfd, path, flags, varargs) {
+ SYSCALLS.varargs = varargs;
+ try {
+
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ var mode = varargs ? syscallGetVarargI() : 0;
+ return FS.open(path, flags, mode).fd;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+
+
+ function ___syscall_readlinkat(dirfd, path, buf, bufsize) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ if (bufsize <= 0) return -28;
+ var ret = FS.readlink(path);
+
+ var len = Math.min(bufsize, lengthBytesUTF8(ret));
+ var endChar = HEAP8[buf+len];
+ stringToUTF8(ret, buf, bufsize+1);
+ // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!)
+ // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write.
+ HEAP8[buf+len] = endChar;
+ return len;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_rmdir(path) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ FS.rmdir(path);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_stat64(path, buf) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ return SYSCALLS.doStat(FS.stat, path, buf);
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ function ___syscall_unlinkat(dirfd, path, flags) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ if (flags === 0) {
+ FS.unlink(path);
+ } else if (flags === 512) {
+ FS.rmdir(path);
+ } else {
+ abort('Invalid flags passed to unlinkat');
+ }
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ var readI53FromI64 = (ptr) => {
+ return HEAPU32[((ptr)>>2)] + HEAP32[(((ptr)+(4))>>2)] * 4294967296;
+ };
+
+ function ___syscall_utimensat(dirfd, path, times, flags) {
+ try {
+
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path, true);
+ var now = Date.now(), atime, mtime;
+ if (!times) {
+ atime = now;
+ mtime = now;
+ } else {
+ var seconds = readI53FromI64(times);
+ var nanoseconds = HEAP32[(((times)+(8))>>2)];
+ if (nanoseconds == 1073741823) {
+ atime = now;
+ } else if (nanoseconds == 1073741822) {
+ atime = -1;
+ } else {
+ atime = (seconds*1000) + (nanoseconds/(1000*1000));
+ }
+ times += 16;
+ seconds = readI53FromI64(times);
+ nanoseconds = HEAP32[(((times)+(8))>>2)];
+ if (nanoseconds == 1073741823) {
+ mtime = now;
+ } else if (nanoseconds == 1073741822) {
+ mtime = -1;
+ } else {
+ mtime = (seconds*1000) + (nanoseconds/(1000*1000));
+ }
+ }
+ // -1 here means UTIME_OMIT was passed. FS.utime tables the max of these
+ // two values and sets the timestamp to that single value. If both were
+ // set to UTIME_OMIT then we can skip the call completely.
+ if (mtime != -1 || atime != -1) {
+ FS.utime(path, atime, mtime);
+ }
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ }
+
+ var nowIsMonotonic = 1;
+ var __emscripten_get_now_is_monotonic = () => nowIsMonotonic;
+
+ var isLeapYear = (year) => year%4 === 0 && (year%100 !== 0 || year%400 === 0);
+
+ var MONTH_DAYS_LEAP_CUMULATIVE = [0,31,60,91,121,152,182,213,244,274,305,335];
+
+ var MONTH_DAYS_REGULAR_CUMULATIVE = [0,31,59,90,120,151,181,212,243,273,304,334];
+ var ydayFromDate = (date) => {
+ var leap = isLeapYear(date.getFullYear());
+ var monthDaysCumulative = (leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE);
+ var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; // -1 since it's days since Jan 1
+
+ return yday;
+ };
+
+ function __localtime_js(time, tmPtr) {
+ time = bigintToI53Checked(time);
+
+
+ var date = new Date(time*1000);
+ HEAP32[((tmPtr)>>2)] = date.getSeconds();
+ HEAP32[(((tmPtr)+(4))>>2)] = date.getMinutes();
+ HEAP32[(((tmPtr)+(8))>>2)] = date.getHours();
+ HEAP32[(((tmPtr)+(12))>>2)] = date.getDate();
+ HEAP32[(((tmPtr)+(16))>>2)] = date.getMonth();
+ HEAP32[(((tmPtr)+(20))>>2)] = date.getFullYear()-1900;
+ HEAP32[(((tmPtr)+(24))>>2)] = date.getDay();
+
+ var yday = ydayFromDate(date)|0;
+ HEAP32[(((tmPtr)+(28))>>2)] = yday;
+ HEAP32[(((tmPtr)+(36))>>2)] = -(date.getTimezoneOffset() * 60);
+
+ // Attention: DST is in December in South, and some regions don't have DST at all.
+ var start = new Date(date.getFullYear(), 0, 1);
+ var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset();
+ var winterOffset = start.getTimezoneOffset();
+ var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0;
+ HEAP32[(((tmPtr)+(32))>>2)] = dst;
+ ;
+ }
+
+
+
+
+
+
+ function __mmap_js(len, prot, flags, fd, offset, allocated, addr) {
+ offset = bigintToI53Checked(offset);
+
+
+ try {
+
+ if (isNaN(offset)) return 61;
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var res = FS.mmap(stream, len, offset, prot, flags);
+ var ptr = res.ptr;
+ HEAP32[((allocated)>>2)] = res.allocated;
+ HEAPU32[((addr)>>2)] = ptr;
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ ;
+ }
+
+
+ function __munmap_js(addr, len, prot, flags, fd, offset) {
+ offset = bigintToI53Checked(offset);
+
+
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ if (prot & 2) {
+ SYSCALLS.doMsync(addr, stream, len, flags, offset);
+ }
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return -e.errno;
+ }
+ ;
+ }
+
+ var __tzset_js = (timezone, daylight, std_name, dst_name) => {
+ // TODO: Use (malleable) environment variables instead of system settings.
+ var currentYear = new Date().getFullYear();
+ var winter = new Date(currentYear, 0, 1);
+ var summer = new Date(currentYear, 6, 1);
+ var winterOffset = winter.getTimezoneOffset();
+ var summerOffset = summer.getTimezoneOffset();
+
+ // Local standard timezone offset. Local standard time is not adjusted for
+ // daylight savings. This code uses the fact that getTimezoneOffset returns
+ // a greater value during Standard Time versus Daylight Saving Time (DST).
+ // Thus it determines the expected output during Standard Time, and it
+ // compares whether the output of the given date the same (Standard) or less
+ // (DST).
+ var stdTimezoneOffset = Math.max(winterOffset, summerOffset);
+
+ // timezone is specified as seconds west of UTC ("The external variable
+ // `timezone` shall be set to the difference, in seconds, between
+ // Coordinated Universal Time (UTC) and local standard time."), the same
+ // as returned by stdTimezoneOffset.
+ // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html
+ HEAPU32[((timezone)>>2)] = stdTimezoneOffset * 60;
+
+ HEAP32[((daylight)>>2)] = Number(winterOffset != summerOffset);
+
+ var extractZone = (timezoneOffset) => {
+ // Why inverse sign?
+ // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
+ var sign = timezoneOffset >= 0 ? "-" : "+";
+
+ var absOffset = Math.abs(timezoneOffset)
+ var hours = String(Math.floor(absOffset / 60)).padStart(2, "0");
+ var minutes = String(absOffset % 60).padStart(2, "0");
+
+ return `UTC${sign}${hours}${minutes}`;
+ }
+
+ var winterName = extractZone(winterOffset);
+ var summerName = extractZone(summerOffset);
+ if (summerOffset < winterOffset) {
+ // Northern hemisphere
+ stringToUTF8(winterName, std_name, 17);
+ stringToUTF8(summerName, dst_name, 17);
+ } else {
+ stringToUTF8(winterName, dst_name, 17);
+ stringToUTF8(summerName, std_name, 17);
+ }
+ };
+
+ var _emscripten_date_now = () => Date.now();
+
+ var _emscripten_get_now = () => performance.now();
+
+ var getHeapMax = () =>
+ // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
+ // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
+ // for any code that deals with heap sizes, which would require special
+ // casing all heap size related code to treat 0 specially.
+ 2147483648;
+
+
+ var abortOnCannotGrowMemory = (requestedSize) => {
+ abort('OOM');
+ };
+
+ var growMemory = (size) => {
+ var b = wasmMemory.buffer;
+ var pages = ((size - b.byteLength + 65535) / 65536) | 0;
+ try {
+ // round size grow request up to wasm page size (fixed 64KB per spec)
+ wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size
+ updateMemoryViews();
+ return 1 /*success*/;
+ } catch(e) {
+ }
+ // implicit 0 return to save code size (caller will cast "undefined" into 0
+ // anyhow)
+ };
+ var _emscripten_resize_heap = (requestedSize) => {
+ var oldSize = HEAPU8.length;
+ // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
+ requestedSize >>>= 0;
+ // With multithreaded builds, races can happen (another thread might increase the size
+ // in between), so return a failure, and let the caller retry.
+
+ // Memory resize rules:
+ // 1. Always increase heap size to at least the requested size, rounded up
+ // to next page multiple.
+ // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
+ // geometrically: increase the heap size according to
+ // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
+ // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
+ // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
+ // linearly: increase the heap size by at least
+ // MEMORY_GROWTH_LINEAR_STEP bytes.
+ // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
+ // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
+ // 4. If we were unable to allocate as much memory, it may be due to
+ // over-eager decision to excessively reserve due to (3) above.
+ // Hence if an allocation fails, cut down on the amount of excess
+ // growth, in an attempt to succeed to perform a smaller allocation.
+
+ // A limit is set for how much we can grow. We should not exceed that
+ // (the wasm binary specifies it, so if we tried, we'd fail anyhow).
+ var maxHeapSize = getHeapMax();
+ if (requestedSize > maxHeapSize) {
+ abortOnCannotGrowMemory(requestedSize);
+ }
+
+ // Loop through potential heap size increases. If we attempt a too eager
+ // reservation that fails, cut down on the attempted size and reserve a
+ // smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
+ for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
+ var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth
+ // but limit overreserving (default to capping at +96MB overgrowth at most)
+ overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 );
+
+ var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536));
+
+ var replacement = growMemory(newSize);
+ if (replacement) {
+
+ return true;
+ }
+ }
+ abortOnCannotGrowMemory(requestedSize);
+ };
+
+ var ENV = {
+ };
+
+ var getExecutableName = () => {
+ return thisProgram || './this.program';
+ };
+ var getEnvStrings = () => {
+ if (!getEnvStrings.strings) {
+ // Default values.
+ // Browser language detection #8751
+ var lang = ((typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8';
+ var env = {
+ 'USER': 'web_user',
+ 'LOGNAME': 'web_user',
+ 'PATH': '/',
+ 'PWD': '/',
+ 'HOME': '/home/web_user',
+ 'LANG': lang,
+ '_': getExecutableName()
+ };
+ // Apply the user-provided values, if any.
+ for (var x in ENV) {
+ // x is a key in ENV; if ENV[x] is undefined, that means it was
+ // explicitly set to be so. We allow user code to do that to
+ // force variables with default values to remain unset.
+ if (ENV[x] === undefined) delete env[x];
+ else env[x] = ENV[x];
+ }
+ var strings = [];
+ for (var x in env) {
+ strings.push(`${x}=${env[x]}`);
+ }
+ getEnvStrings.strings = strings;
+ }
+ return getEnvStrings.strings;
+ };
+
+ var stringToAscii = (str, buffer) => {
+ for (var i = 0; i < str.length; ++i) {
+ HEAP8[buffer++] = str.charCodeAt(i);
+ }
+ // Null-terminate the string
+ HEAP8[buffer] = 0;
+ };
+ var _environ_get = (__environ, environ_buf) => {
+ var bufSize = 0;
+ getEnvStrings().forEach((string, i) => {
+ var ptr = environ_buf + bufSize;
+ HEAPU32[(((__environ)+(i*4))>>2)] = ptr;
+ stringToAscii(string, ptr);
+ bufSize += string.length + 1;
+ });
+ return 0;
+ };
+
+ var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
+ var strings = getEnvStrings();
+ HEAPU32[((penviron_count)>>2)] = strings.length;
+ var bufSize = 0;
+ strings.forEach((string) => bufSize += string.length + 1);
+ HEAPU32[((penviron_buf_size)>>2)] = bufSize;
+ return 0;
+ };
+
+
+ var runtimeKeepaliveCounter = 0;
+ var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
+ var _proc_exit = (code) => {
+ EXITSTATUS = code;
+ if (!keepRuntimeAlive()) {
+ Module['onExit']?.(code);
+ ABORT = true;
+ }
+ quit_(code, new ExitStatus(code));
+ };
+ /** @suppress {duplicate } */
+ /** @param {boolean|number=} implicit */
+ var exitJS = (status, implicit) => {
+ EXITSTATUS = status;
+
+ _proc_exit(status);
+ };
+ var _exit = exitJS;
+
+ function _fd_close(fd) {
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ FS.close(stream);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return e.errno;
+ }
+ }
+
+ function _fd_fdstat_get(fd, pbuf) {
+ try {
+
+ var rightsBase = 0;
+ var rightsInheriting = 0;
+ var flags = 0;
+ {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ // All character devices are terminals (other things a Linux system would
+ // assume is a character device, like the mouse, we have special APIs for).
+ var type = stream.tty ? 2 :
+ FS.isDir(stream.mode) ? 3 :
+ FS.isLink(stream.mode) ? 7 :
+ 4;
+ }
+ HEAP8[pbuf] = type;
+ HEAP16[(((pbuf)+(2))>>1)] = flags;
+ HEAP64[(((pbuf)+(8))>>3)] = BigInt(rightsBase);
+ HEAP64[(((pbuf)+(16))>>3)] = BigInt(rightsInheriting);
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return e.errno;
+ }
+ }
+
+ /** @param {number=} offset */
+ var doReadv = (stream, iov, iovcnt, offset) => {
+ var ret = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[((iov)>>2)];
+ var len = HEAPU32[(((iov)+(4))>>2)];
+ iov += 8;
+ var curr = FS.read(stream, HEAP8, ptr, len, offset);
+ if (curr < 0) return -1;
+ ret += curr;
+ if (curr < len) break; // nothing more to read
+ if (typeof offset != 'undefined') {
+ offset += curr;
+ }
+ }
+ return ret;
+ };
+
+ function _fd_read(fd, iov, iovcnt, pnum) {
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var num = doReadv(stream, iov, iovcnt);
+ HEAPU32[((pnum)>>2)] = num;
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return e.errno;
+ }
+ }
+
+
+ function _fd_seek(fd, offset, whence, newOffset) {
+ offset = bigintToI53Checked(offset);
+
+
+ try {
+
+ if (isNaN(offset)) return 61;
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ FS.llseek(stream, offset, whence);
+ HEAP64[((newOffset)>>3)] = BigInt(stream.position);
+ if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return e.errno;
+ }
+ ;
+ }
+
+ function _fd_sync(fd) {
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ if (stream.stream_ops?.fsync) {
+ return stream.stream_ops.fsync(stream);
+ }
+ return 0; // we can't do anything synchronously; the in-memory FS is already synced to
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return e.errno;
+ }
+ }
+
+ /** @param {number=} offset */
+ var doWritev = (stream, iov, iovcnt, offset) => {
+ var ret = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[((iov)>>2)];
+ var len = HEAPU32[(((iov)+(4))>>2)];
+ iov += 8;
+ var curr = FS.write(stream, HEAP8, ptr, len, offset);
+ if (curr < 0) return -1;
+ ret += curr;
+ if (curr < len) {
+ // No more space to write.
+ break;
+ }
+ if (typeof offset != 'undefined') {
+ offset += curr;
+ }
+ }
+ return ret;
+ };
+
+ function _fd_write(fd, iov, iovcnt, pnum) {
+ try {
+
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var num = doWritev(stream, iov, iovcnt);
+ HEAPU32[((pnum)>>2)] = num;
+ return 0;
+ } catch (e) {
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
+ return e.errno;
+ }
+ }
+
+ FS.createPreloadedFile = FS_createPreloadedFile;
+ FS.staticInit();
+ // Set module methods based on EXPORTED_RUNTIME_METHODS
+ ;
+var wasmImports = {
+ /** @export */
+ __assert_fail: ___assert_fail,
+ /** @export */
+ __syscall_chmod: ___syscall_chmod,
+ /** @export */
+ __syscall_faccessat: ___syscall_faccessat,
+ /** @export */
+ __syscall_fchmod: ___syscall_fchmod,
+ /** @export */
+ __syscall_fchown32: ___syscall_fchown32,
+ /** @export */
+ __syscall_fcntl64: ___syscall_fcntl64,
+ /** @export */
+ __syscall_fstat64: ___syscall_fstat64,
+ /** @export */
+ __syscall_ftruncate64: ___syscall_ftruncate64,
+ /** @export */
+ __syscall_getcwd: ___syscall_getcwd,
+ /** @export */
+ __syscall_ioctl: ___syscall_ioctl,
+ /** @export */
+ __syscall_lstat64: ___syscall_lstat64,
+ /** @export */
+ __syscall_mkdirat: ___syscall_mkdirat,
+ /** @export */
+ __syscall_newfstatat: ___syscall_newfstatat,
+ /** @export */
+ __syscall_openat: ___syscall_openat,
+ /** @export */
+ __syscall_readlinkat: ___syscall_readlinkat,
+ /** @export */
+ __syscall_rmdir: ___syscall_rmdir,
+ /** @export */
+ __syscall_stat64: ___syscall_stat64,
+ /** @export */
+ __syscall_unlinkat: ___syscall_unlinkat,
+ /** @export */
+ __syscall_utimensat: ___syscall_utimensat,
+ /** @export */
+ _emscripten_get_now_is_monotonic: __emscripten_get_now_is_monotonic,
+ /** @export */
+ _localtime_js: __localtime_js,
+ /** @export */
+ _mmap_js: __mmap_js,
+ /** @export */
+ _munmap_js: __munmap_js,
+ /** @export */
+ _tzset_js: __tzset_js,
+ /** @export */
+ emscripten_date_now: _emscripten_date_now,
+ /** @export */
+ emscripten_get_now: _emscripten_get_now,
+ /** @export */
+ emscripten_resize_heap: _emscripten_resize_heap,
+ /** @export */
+ environ_get: _environ_get,
+ /** @export */
+ environ_sizes_get: _environ_sizes_get,
+ /** @export */
+ exit: _exit,
+ /** @export */
+ fd_close: _fd_close,
+ /** @export */
+ fd_fdstat_get: _fd_fdstat_get,
+ /** @export */
+ fd_read: _fd_read,
+ /** @export */
+ fd_seek: _fd_seek,
+ /** @export */
+ fd_sync: _fd_sync,
+ /** @export */
+ fd_write: _fd_write
+};
+var wasmExports = createWasm();
+var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports['__wasm_call_ctors'])();
+var _sqlite3_vfs_find = Module['_sqlite3_vfs_find'] = (a0) => (_sqlite3_vfs_find = Module['_sqlite3_vfs_find'] = wasmExports['sqlite3_vfs_find'])(a0);
+var _sqlite3_free = Module['_sqlite3_free'] = (a0) => (_sqlite3_free = Module['_sqlite3_free'] = wasmExports['sqlite3_free'])(a0);
+var _sqlite3_finalize = Module['_sqlite3_finalize'] = (a0) => (_sqlite3_finalize = Module['_sqlite3_finalize'] = wasmExports['sqlite3_finalize'])(a0);
+var _sqlite3_exec = Module['_sqlite3_exec'] = (a0, a1, a2, a3, a4) => (_sqlite3_exec = Module['_sqlite3_exec'] = wasmExports['sqlite3_exec'])(a0, a1, a2, a3, a4);
+var _sqlite3_errmsg = Module['_sqlite3_errmsg'] = (a0) => (_sqlite3_errmsg = Module['_sqlite3_errmsg'] = wasmExports['sqlite3_errmsg'])(a0);
+var _sqlite3_strglob = Module['_sqlite3_strglob'] = (a0, a1) => (_sqlite3_strglob = Module['_sqlite3_strglob'] = wasmExports['sqlite3_strglob'])(a0, a1);
+var _sqlite3_prepare_v2 = Module['_sqlite3_prepare_v2'] = (a0, a1, a2, a3, a4) => (_sqlite3_prepare_v2 = Module['_sqlite3_prepare_v2'] = wasmExports['sqlite3_prepare_v2'])(a0, a1, a2, a3, a4);
+var _sqlite3_expanded_sql = Module['_sqlite3_expanded_sql'] = (a0) => (_sqlite3_expanded_sql = Module['_sqlite3_expanded_sql'] = wasmExports['sqlite3_expanded_sql'])(a0);
+var _sqlite3_step = Module['_sqlite3_step'] = (a0) => (_sqlite3_step = Module['_sqlite3_step'] = wasmExports['sqlite3_step'])(a0);
+var _sqlite3_column_text = Module['_sqlite3_column_text'] = (a0, a1) => (_sqlite3_column_text = Module['_sqlite3_column_text'] = wasmExports['sqlite3_column_text'])(a0, a1);
+var _sqlite3_column_count = Module['_sqlite3_column_count'] = (a0) => (_sqlite3_column_count = Module['_sqlite3_column_count'] = wasmExports['sqlite3_column_count'])(a0);
+var _sqlite3_column_type = Module['_sqlite3_column_type'] = (a0, a1) => (_sqlite3_column_type = Module['_sqlite3_column_type'] = wasmExports['sqlite3_column_type'])(a0, a1);
+var _sqlite3_column_bytes = Module['_sqlite3_column_bytes'] = (a0, a1) => (_sqlite3_column_bytes = Module['_sqlite3_column_bytes'] = wasmExports['sqlite3_column_bytes'])(a0, a1);
+var _sqlite3_column_blob = Module['_sqlite3_column_blob'] = (a0, a1) => (_sqlite3_column_blob = Module['_sqlite3_column_blob'] = wasmExports['sqlite3_column_blob'])(a0, a1);
+var _sqlite3_sql = Module['_sqlite3_sql'] = (a0) => (_sqlite3_sql = Module['_sqlite3_sql'] = wasmExports['sqlite3_sql'])(a0);
+var _sqlite3_reset = Module['_sqlite3_reset'] = (a0) => (_sqlite3_reset = Module['_sqlite3_reset'] = wasmExports['sqlite3_reset'])(a0);
+var _sqlite3_bind_int64 = Module['_sqlite3_bind_int64'] = (a0, a1, a2) => (_sqlite3_bind_int64 = Module['_sqlite3_bind_int64'] = wasmExports['sqlite3_bind_int64'])(a0, a1, a2);
+var _sqlite3_bind_int = Module['_sqlite3_bind_int'] = (a0, a1, a2) => (_sqlite3_bind_int = Module['_sqlite3_bind_int'] = wasmExports['sqlite3_bind_int'])(a0, a1, a2);
+var _sqlite3_bind_text = Module['_sqlite3_bind_text'] = (a0, a1, a2, a3, a4) => (_sqlite3_bind_text = Module['_sqlite3_bind_text'] = wasmExports['sqlite3_bind_text'])(a0, a1, a2, a3, a4);
+var _sqlite3_libversion_number = Module['_sqlite3_libversion_number'] = () => (_sqlite3_libversion_number = Module['_sqlite3_libversion_number'] = wasmExports['sqlite3_libversion_number'])();
+var _sqlite3_bind_double = Module['_sqlite3_bind_double'] = (a0, a1, a2) => (_sqlite3_bind_double = Module['_sqlite3_bind_double'] = wasmExports['sqlite3_bind_double'])(a0, a1, a2);
+var _sqlite3_malloc = Module['_sqlite3_malloc'] = (a0) => (_sqlite3_malloc = Module['_sqlite3_malloc'] = wasmExports['sqlite3_malloc'])(a0);
+var _sqlite3_libversion = Module['_sqlite3_libversion'] = () => (_sqlite3_libversion = Module['_sqlite3_libversion'] = wasmExports['sqlite3_libversion'])();
+var _sqlite3_sourceid = Module['_sqlite3_sourceid'] = () => (_sqlite3_sourceid = Module['_sqlite3_sourceid'] = wasmExports['sqlite3_sourceid'])();
+var _malloc = Module['_malloc'] = (a0) => (_malloc = Module['_malloc'] = wasmExports['malloc'])(a0);
+var _sqlite3_initialize = Module['_sqlite3_initialize'] = () => (_sqlite3_initialize = Module['_sqlite3_initialize'] = wasmExports['sqlite3_initialize'])();
+var _sqlite3_open_v2 = Module['_sqlite3_open_v2'] = (a0, a1, a2, a3) => (_sqlite3_open_v2 = Module['_sqlite3_open_v2'] = wasmExports['sqlite3_open_v2'])(a0, a1, a2, a3);
+var _sqlite3_file_control = Module['_sqlite3_file_control'] = (a0, a1, a2, a3) => (_sqlite3_file_control = Module['_sqlite3_file_control'] = wasmExports['sqlite3_file_control'])(a0, a1, a2, a3);
+var _sqlite3_create_function = Module['_sqlite3_create_function'] = (a0, a1, a2, a3, a4, a5, a6, a7) => (_sqlite3_create_function = Module['_sqlite3_create_function'] = wasmExports['sqlite3_create_function'])(a0, a1, a2, a3, a4, a5, a6, a7);
+var _sqlite3_db_status = Module['_sqlite3_db_status'] = (a0, a1, a2, a3, a4) => (_sqlite3_db_status = Module['_sqlite3_db_status'] = wasmExports['sqlite3_db_status'])(a0, a1, a2, a3, a4);
+var _sqlite3_status = Module['_sqlite3_status'] = (a0, a1, a2, a3) => (_sqlite3_status = Module['_sqlite3_status'] = wasmExports['sqlite3_status'])(a0, a1, a2, a3);
+var _free = Module['_free'] = (a0) => (_free = Module['_free'] = wasmExports['free'])(a0);
+var _sqlite3_stricmp = Module['_sqlite3_stricmp'] = (a0, a1) => (_sqlite3_stricmp = Module['_sqlite3_stricmp'] = wasmExports['sqlite3_stricmp'])(a0, a1);
+var _sqlite3_result_int64 = Module['_sqlite3_result_int64'] = (a0, a1) => (_sqlite3_result_int64 = Module['_sqlite3_result_int64'] = wasmExports['sqlite3_result_int64'])(a0, a1);
+var _wasm_main = Module['_wasm_main'] = (a0, a1) => (_wasm_main = Module['_wasm_main'] = wasmExports['wasm_main'])(a0, a1);
+var _sqlite3_status64 = Module['_sqlite3_status64'] = (a0, a1, a2, a3) => (_sqlite3_status64 = Module['_sqlite3_status64'] = wasmExports['sqlite3_status64'])(a0, a1, a2, a3);
+var _sqlite3_msize = Module['_sqlite3_msize'] = (a0) => (_sqlite3_msize = Module['_sqlite3_msize'] = wasmExports['sqlite3_msize'])(a0);
+var _sqlite3_vfs_register = Module['_sqlite3_vfs_register'] = (a0, a1) => (_sqlite3_vfs_register = Module['_sqlite3_vfs_register'] = wasmExports['sqlite3_vfs_register'])(a0, a1);
+var _sqlite3_vfs_unregister = Module['_sqlite3_vfs_unregister'] = (a0) => (_sqlite3_vfs_unregister = Module['_sqlite3_vfs_unregister'] = wasmExports['sqlite3_vfs_unregister'])(a0);
+var _sqlite3_malloc64 = Module['_sqlite3_malloc64'] = (a0) => (_sqlite3_malloc64 = Module['_sqlite3_malloc64'] = wasmExports['sqlite3_malloc64'])(a0);
+var _sqlite3_realloc = Module['_sqlite3_realloc'] = (a0, a1) => (_sqlite3_realloc = Module['_sqlite3_realloc'] = wasmExports['sqlite3_realloc'])(a0, a1);
+var _sqlite3_realloc64 = Module['_sqlite3_realloc64'] = (a0, a1) => (_sqlite3_realloc64 = Module['_sqlite3_realloc64'] = wasmExports['sqlite3_realloc64'])(a0, a1);
+var _sqlite3_value_text = Module['_sqlite3_value_text'] = (a0) => (_sqlite3_value_text = Module['_sqlite3_value_text'] = wasmExports['sqlite3_value_text'])(a0);
+var _sqlite3_randomness = Module['_sqlite3_randomness'] = (a0, a1) => (_sqlite3_randomness = Module['_sqlite3_randomness'] = wasmExports['sqlite3_randomness'])(a0, a1);
+var _sqlite3_strnicmp = Module['_sqlite3_strnicmp'] = (a0, a1, a2) => (_sqlite3_strnicmp = Module['_sqlite3_strnicmp'] = wasmExports['sqlite3_strnicmp'])(a0, a1, a2);
+var _sqlite3_uri_parameter = Module['_sqlite3_uri_parameter'] = (a0, a1) => (_sqlite3_uri_parameter = Module['_sqlite3_uri_parameter'] = wasmExports['sqlite3_uri_parameter'])(a0, a1);
+var _sqlite3_uri_boolean = Module['_sqlite3_uri_boolean'] = (a0, a1, a2) => (_sqlite3_uri_boolean = Module['_sqlite3_uri_boolean'] = wasmExports['sqlite3_uri_boolean'])(a0, a1, a2);
+var _sqlite3_serialize = Module['_sqlite3_serialize'] = (a0, a1, a2, a3) => (_sqlite3_serialize = Module['_sqlite3_serialize'] = wasmExports['sqlite3_serialize'])(a0, a1, a2, a3);
+var _sqlite3_column_int64 = Module['_sqlite3_column_int64'] = (a0, a1) => (_sqlite3_column_int64 = Module['_sqlite3_column_int64'] = wasmExports['sqlite3_column_int64'])(a0, a1);
+var _sqlite3_column_int = Module['_sqlite3_column_int'] = (a0, a1) => (_sqlite3_column_int = Module['_sqlite3_column_int'] = wasmExports['sqlite3_column_int'])(a0, a1);
+var _sqlite3_column_name = Module['_sqlite3_column_name'] = (a0, a1) => (_sqlite3_column_name = Module['_sqlite3_column_name'] = wasmExports['sqlite3_column_name'])(a0, a1);
+var _sqlite3_deserialize = Module['_sqlite3_deserialize'] = (a0, a1, a2, a3, a4, a5) => (_sqlite3_deserialize = Module['_sqlite3_deserialize'] = wasmExports['sqlite3_deserialize'])(a0, a1, a2, a3, a4, a5);
+var _sqlite3_clear_bindings = Module['_sqlite3_clear_bindings'] = (a0) => (_sqlite3_clear_bindings = Module['_sqlite3_clear_bindings'] = wasmExports['sqlite3_clear_bindings'])(a0);
+var _sqlite3_value_blob = Module['_sqlite3_value_blob'] = (a0) => (_sqlite3_value_blob = Module['_sqlite3_value_blob'] = wasmExports['sqlite3_value_blob'])(a0);
+var _sqlite3_value_bytes = Module['_sqlite3_value_bytes'] = (a0) => (_sqlite3_value_bytes = Module['_sqlite3_value_bytes'] = wasmExports['sqlite3_value_bytes'])(a0);
+var _sqlite3_value_double = Module['_sqlite3_value_double'] = (a0) => (_sqlite3_value_double = Module['_sqlite3_value_double'] = wasmExports['sqlite3_value_double'])(a0);
+var _sqlite3_value_int = Module['_sqlite3_value_int'] = (a0) => (_sqlite3_value_int = Module['_sqlite3_value_int'] = wasmExports['sqlite3_value_int'])(a0);
+var _sqlite3_value_int64 = Module['_sqlite3_value_int64'] = (a0) => (_sqlite3_value_int64 = Module['_sqlite3_value_int64'] = wasmExports['sqlite3_value_int64'])(a0);
+var _sqlite3_value_subtype = Module['_sqlite3_value_subtype'] = (a0) => (_sqlite3_value_subtype = Module['_sqlite3_value_subtype'] = wasmExports['sqlite3_value_subtype'])(a0);
+var _sqlite3_value_pointer = Module['_sqlite3_value_pointer'] = (a0, a1) => (_sqlite3_value_pointer = Module['_sqlite3_value_pointer'] = wasmExports['sqlite3_value_pointer'])(a0, a1);
+var _sqlite3_value_type = Module['_sqlite3_value_type'] = (a0) => (_sqlite3_value_type = Module['_sqlite3_value_type'] = wasmExports['sqlite3_value_type'])(a0);
+var _sqlite3_value_nochange = Module['_sqlite3_value_nochange'] = (a0) => (_sqlite3_value_nochange = Module['_sqlite3_value_nochange'] = wasmExports['sqlite3_value_nochange'])(a0);
+var _sqlite3_value_frombind = Module['_sqlite3_value_frombind'] = (a0) => (_sqlite3_value_frombind = Module['_sqlite3_value_frombind'] = wasmExports['sqlite3_value_frombind'])(a0);
+var _sqlite3_value_dup = Module['_sqlite3_value_dup'] = (a0) => (_sqlite3_value_dup = Module['_sqlite3_value_dup'] = wasmExports['sqlite3_value_dup'])(a0);
+var _sqlite3_value_free = Module['_sqlite3_value_free'] = (a0) => (_sqlite3_value_free = Module['_sqlite3_value_free'] = wasmExports['sqlite3_value_free'])(a0);
+var _sqlite3_result_blob = Module['_sqlite3_result_blob'] = (a0, a1, a2, a3) => (_sqlite3_result_blob = Module['_sqlite3_result_blob'] = wasmExports['sqlite3_result_blob'])(a0, a1, a2, a3);
+var _sqlite3_result_error_toobig = Module['_sqlite3_result_error_toobig'] = (a0) => (_sqlite3_result_error_toobig = Module['_sqlite3_result_error_toobig'] = wasmExports['sqlite3_result_error_toobig'])(a0);
+var _sqlite3_result_error_nomem = Module['_sqlite3_result_error_nomem'] = (a0) => (_sqlite3_result_error_nomem = Module['_sqlite3_result_error_nomem'] = wasmExports['sqlite3_result_error_nomem'])(a0);
+var _sqlite3_result_double = Module['_sqlite3_result_double'] = (a0, a1) => (_sqlite3_result_double = Module['_sqlite3_result_double'] = wasmExports['sqlite3_result_double'])(a0, a1);
+var _sqlite3_result_error = Module['_sqlite3_result_error'] = (a0, a1, a2) => (_sqlite3_result_error = Module['_sqlite3_result_error'] = wasmExports['sqlite3_result_error'])(a0, a1, a2);
+var _sqlite3_result_int = Module['_sqlite3_result_int'] = (a0, a1) => (_sqlite3_result_int = Module['_sqlite3_result_int'] = wasmExports['sqlite3_result_int'])(a0, a1);
+var _sqlite3_result_null = Module['_sqlite3_result_null'] = (a0) => (_sqlite3_result_null = Module['_sqlite3_result_null'] = wasmExports['sqlite3_result_null'])(a0);
+var _sqlite3_result_pointer = Module['_sqlite3_result_pointer'] = (a0, a1, a2, a3) => (_sqlite3_result_pointer = Module['_sqlite3_result_pointer'] = wasmExports['sqlite3_result_pointer'])(a0, a1, a2, a3);
+var _sqlite3_result_subtype = Module['_sqlite3_result_subtype'] = (a0, a1) => (_sqlite3_result_subtype = Module['_sqlite3_result_subtype'] = wasmExports['sqlite3_result_subtype'])(a0, a1);
+var _sqlite3_result_text = Module['_sqlite3_result_text'] = (a0, a1, a2, a3) => (_sqlite3_result_text = Module['_sqlite3_result_text'] = wasmExports['sqlite3_result_text'])(a0, a1, a2, a3);
+var _sqlite3_result_zeroblob = Module['_sqlite3_result_zeroblob'] = (a0, a1) => (_sqlite3_result_zeroblob = Module['_sqlite3_result_zeroblob'] = wasmExports['sqlite3_result_zeroblob'])(a0, a1);
+var _sqlite3_result_zeroblob64 = Module['_sqlite3_result_zeroblob64'] = (a0, a1) => (_sqlite3_result_zeroblob64 = Module['_sqlite3_result_zeroblob64'] = wasmExports['sqlite3_result_zeroblob64'])(a0, a1);
+var _sqlite3_result_error_code = Module['_sqlite3_result_error_code'] = (a0, a1) => (_sqlite3_result_error_code = Module['_sqlite3_result_error_code'] = wasmExports['sqlite3_result_error_code'])(a0, a1);
+var _sqlite3_user_data = Module['_sqlite3_user_data'] = (a0) => (_sqlite3_user_data = Module['_sqlite3_user_data'] = wasmExports['sqlite3_user_data'])(a0);
+var _sqlite3_context_db_handle = Module['_sqlite3_context_db_handle'] = (a0) => (_sqlite3_context_db_handle = Module['_sqlite3_context_db_handle'] = wasmExports['sqlite3_context_db_handle'])(a0);
+var _sqlite3_vtab_nochange = Module['_sqlite3_vtab_nochange'] = (a0) => (_sqlite3_vtab_nochange = Module['_sqlite3_vtab_nochange'] = wasmExports['sqlite3_vtab_nochange'])(a0);
+var _sqlite3_vtab_in_first = Module['_sqlite3_vtab_in_first'] = (a0, a1) => (_sqlite3_vtab_in_first = Module['_sqlite3_vtab_in_first'] = wasmExports['sqlite3_vtab_in_first'])(a0, a1);
+var _sqlite3_vtab_in_next = Module['_sqlite3_vtab_in_next'] = (a0, a1) => (_sqlite3_vtab_in_next = Module['_sqlite3_vtab_in_next'] = wasmExports['sqlite3_vtab_in_next'])(a0, a1);
+var _sqlite3_aggregate_context = Module['_sqlite3_aggregate_context'] = (a0, a1) => (_sqlite3_aggregate_context = Module['_sqlite3_aggregate_context'] = wasmExports['sqlite3_aggregate_context'])(a0, a1);
+var _sqlite3_get_auxdata = Module['_sqlite3_get_auxdata'] = (a0, a1) => (_sqlite3_get_auxdata = Module['_sqlite3_get_auxdata'] = wasmExports['sqlite3_get_auxdata'])(a0, a1);
+var _sqlite3_set_auxdata = Module['_sqlite3_set_auxdata'] = (a0, a1, a2, a3) => (_sqlite3_set_auxdata = Module['_sqlite3_set_auxdata'] = wasmExports['sqlite3_set_auxdata'])(a0, a1, a2, a3);
+var _sqlite3_data_count = Module['_sqlite3_data_count'] = (a0) => (_sqlite3_data_count = Module['_sqlite3_data_count'] = wasmExports['sqlite3_data_count'])(a0);
+var _sqlite3_column_double = Module['_sqlite3_column_double'] = (a0, a1) => (_sqlite3_column_double = Module['_sqlite3_column_double'] = wasmExports['sqlite3_column_double'])(a0, a1);
+var _sqlite3_column_value = Module['_sqlite3_column_value'] = (a0, a1) => (_sqlite3_column_value = Module['_sqlite3_column_value'] = wasmExports['sqlite3_column_value'])(a0, a1);
+var _sqlite3_column_decltype = Module['_sqlite3_column_decltype'] = (a0, a1) => (_sqlite3_column_decltype = Module['_sqlite3_column_decltype'] = wasmExports['sqlite3_column_decltype'])(a0, a1);
+var _sqlite3_bind_blob = Module['_sqlite3_bind_blob'] = (a0, a1, a2, a3, a4) => (_sqlite3_bind_blob = Module['_sqlite3_bind_blob'] = wasmExports['sqlite3_bind_blob'])(a0, a1, a2, a3, a4);
+var _sqlite3_bind_null = Module['_sqlite3_bind_null'] = (a0, a1) => (_sqlite3_bind_null = Module['_sqlite3_bind_null'] = wasmExports['sqlite3_bind_null'])(a0, a1);
+var _sqlite3_bind_pointer = Module['_sqlite3_bind_pointer'] = (a0, a1, a2, a3, a4) => (_sqlite3_bind_pointer = Module['_sqlite3_bind_pointer'] = wasmExports['sqlite3_bind_pointer'])(a0, a1, a2, a3, a4);
+var _sqlite3_bind_parameter_count = Module['_sqlite3_bind_parameter_count'] = (a0) => (_sqlite3_bind_parameter_count = Module['_sqlite3_bind_parameter_count'] = wasmExports['sqlite3_bind_parameter_count'])(a0);
+var _sqlite3_bind_parameter_name = Module['_sqlite3_bind_parameter_name'] = (a0, a1) => (_sqlite3_bind_parameter_name = Module['_sqlite3_bind_parameter_name'] = wasmExports['sqlite3_bind_parameter_name'])(a0, a1);
+var _sqlite3_bind_parameter_index = Module['_sqlite3_bind_parameter_index'] = (a0, a1) => (_sqlite3_bind_parameter_index = Module['_sqlite3_bind_parameter_index'] = wasmExports['sqlite3_bind_parameter_index'])(a0, a1);
+var _sqlite3_db_handle = Module['_sqlite3_db_handle'] = (a0) => (_sqlite3_db_handle = Module['_sqlite3_db_handle'] = wasmExports['sqlite3_db_handle'])(a0);
+var _sqlite3_stmt_readonly = Module['_sqlite3_stmt_readonly'] = (a0) => (_sqlite3_stmt_readonly = Module['_sqlite3_stmt_readonly'] = wasmExports['sqlite3_stmt_readonly'])(a0);
+var _sqlite3_stmt_isexplain = Module['_sqlite3_stmt_isexplain'] = (a0) => (_sqlite3_stmt_isexplain = Module['_sqlite3_stmt_isexplain'] = wasmExports['sqlite3_stmt_isexplain'])(a0);
+var _sqlite3_stmt_explain = Module['_sqlite3_stmt_explain'] = (a0, a1) => (_sqlite3_stmt_explain = Module['_sqlite3_stmt_explain'] = wasmExports['sqlite3_stmt_explain'])(a0, a1);
+var _sqlite3_stmt_busy = Module['_sqlite3_stmt_busy'] = (a0) => (_sqlite3_stmt_busy = Module['_sqlite3_stmt_busy'] = wasmExports['sqlite3_stmt_busy'])(a0);
+var _sqlite3_stmt_status = Module['_sqlite3_stmt_status'] = (a0, a1, a2) => (_sqlite3_stmt_status = Module['_sqlite3_stmt_status'] = wasmExports['sqlite3_stmt_status'])(a0, a1, a2);
+var _sqlite3_value_numeric_type = Module['_sqlite3_value_numeric_type'] = (a0) => (_sqlite3_value_numeric_type = Module['_sqlite3_value_numeric_type'] = wasmExports['sqlite3_value_numeric_type'])(a0);
+var _sqlite3_strlike = Module['_sqlite3_strlike'] = (a0, a1, a2) => (_sqlite3_strlike = Module['_sqlite3_strlike'] = wasmExports['sqlite3_strlike'])(a0, a1, a2);
+var _sqlite3_auto_extension = Module['_sqlite3_auto_extension'] = (a0) => (_sqlite3_auto_extension = Module['_sqlite3_auto_extension'] = wasmExports['sqlite3_auto_extension'])(a0);
+var _sqlite3_cancel_auto_extension = Module['_sqlite3_cancel_auto_extension'] = (a0) => (_sqlite3_cancel_auto_extension = Module['_sqlite3_cancel_auto_extension'] = wasmExports['sqlite3_cancel_auto_extension'])(a0);
+var _sqlite3_reset_auto_extension = Module['_sqlite3_reset_auto_extension'] = () => (_sqlite3_reset_auto_extension = Module['_sqlite3_reset_auto_extension'] = wasmExports['sqlite3_reset_auto_extension'])();
+var _sqlite3_prepare_v3 = Module['_sqlite3_prepare_v3'] = (a0, a1, a2, a3, a4, a5) => (_sqlite3_prepare_v3 = Module['_sqlite3_prepare_v3'] = wasmExports['sqlite3_prepare_v3'])(a0, a1, a2, a3, a4, a5);
+var _sqlite3_vtab_on_conflict = Module['_sqlite3_vtab_on_conflict'] = (a0) => (_sqlite3_vtab_on_conflict = Module['_sqlite3_vtab_on_conflict'] = wasmExports['sqlite3_vtab_on_conflict'])(a0);
+var _sqlite3_vtab_collation = Module['_sqlite3_vtab_collation'] = (a0, a1) => (_sqlite3_vtab_collation = Module['_sqlite3_vtab_collation'] = wasmExports['sqlite3_vtab_collation'])(a0, a1);
+var _sqlite3_vtab_in = Module['_sqlite3_vtab_in'] = (a0, a1, a2) => (_sqlite3_vtab_in = Module['_sqlite3_vtab_in'] = wasmExports['sqlite3_vtab_in'])(a0, a1, a2);
+var _sqlite3_vtab_rhs_value = Module['_sqlite3_vtab_rhs_value'] = (a0, a1, a2) => (_sqlite3_vtab_rhs_value = Module['_sqlite3_vtab_rhs_value'] = wasmExports['sqlite3_vtab_rhs_value'])(a0, a1, a2);
+var _sqlite3_vtab_distinct = Module['_sqlite3_vtab_distinct'] = (a0) => (_sqlite3_vtab_distinct = Module['_sqlite3_vtab_distinct'] = wasmExports['sqlite3_vtab_distinct'])(a0);
+var _sqlite3_keyword_name = Module['_sqlite3_keyword_name'] = (a0, a1, a2) => (_sqlite3_keyword_name = Module['_sqlite3_keyword_name'] = wasmExports['sqlite3_keyword_name'])(a0, a1, a2);
+var _sqlite3_keyword_count = Module['_sqlite3_keyword_count'] = () => (_sqlite3_keyword_count = Module['_sqlite3_keyword_count'] = wasmExports['sqlite3_keyword_count'])();
+var _sqlite3_keyword_check = Module['_sqlite3_keyword_check'] = (a0, a1) => (_sqlite3_keyword_check = Module['_sqlite3_keyword_check'] = wasmExports['sqlite3_keyword_check'])(a0, a1);
+var _sqlite3_complete = Module['_sqlite3_complete'] = (a0) => (_sqlite3_complete = Module['_sqlite3_complete'] = wasmExports['sqlite3_complete'])(a0);
+var _sqlite3_shutdown = Module['_sqlite3_shutdown'] = () => (_sqlite3_shutdown = Module['_sqlite3_shutdown'] = wasmExports['sqlite3_shutdown'])();
+var _sqlite3_last_insert_rowid = Module['_sqlite3_last_insert_rowid'] = (a0) => (_sqlite3_last_insert_rowid = Module['_sqlite3_last_insert_rowid'] = wasmExports['sqlite3_last_insert_rowid'])(a0);
+var _sqlite3_set_last_insert_rowid = Module['_sqlite3_set_last_insert_rowid'] = (a0, a1) => (_sqlite3_set_last_insert_rowid = Module['_sqlite3_set_last_insert_rowid'] = wasmExports['sqlite3_set_last_insert_rowid'])(a0, a1);
+var _sqlite3_changes64 = Module['_sqlite3_changes64'] = (a0) => (_sqlite3_changes64 = Module['_sqlite3_changes64'] = wasmExports['sqlite3_changes64'])(a0);
+var _sqlite3_changes = Module['_sqlite3_changes'] = (a0) => (_sqlite3_changes = Module['_sqlite3_changes'] = wasmExports['sqlite3_changes'])(a0);
+var _sqlite3_total_changes64 = Module['_sqlite3_total_changes64'] = (a0) => (_sqlite3_total_changes64 = Module['_sqlite3_total_changes64'] = wasmExports['sqlite3_total_changes64'])(a0);
+var _sqlite3_total_changes = Module['_sqlite3_total_changes'] = (a0) => (_sqlite3_total_changes = Module['_sqlite3_total_changes'] = wasmExports['sqlite3_total_changes'])(a0);
+var _sqlite3_txn_state = Module['_sqlite3_txn_state'] = (a0, a1) => (_sqlite3_txn_state = Module['_sqlite3_txn_state'] = wasmExports['sqlite3_txn_state'])(a0, a1);
+var _sqlite3_close_v2 = Module['_sqlite3_close_v2'] = (a0) => (_sqlite3_close_v2 = Module['_sqlite3_close_v2'] = wasmExports['sqlite3_close_v2'])(a0);
+var _sqlite3_busy_handler = Module['_sqlite3_busy_handler'] = (a0, a1, a2) => (_sqlite3_busy_handler = Module['_sqlite3_busy_handler'] = wasmExports['sqlite3_busy_handler'])(a0, a1, a2);
+var _sqlite3_busy_timeout = Module['_sqlite3_busy_timeout'] = (a0, a1) => (_sqlite3_busy_timeout = Module['_sqlite3_busy_timeout'] = wasmExports['sqlite3_busy_timeout'])(a0, a1);
+var _sqlite3_interrupt = Module['_sqlite3_interrupt'] = (a0) => (_sqlite3_interrupt = Module['_sqlite3_interrupt'] = wasmExports['sqlite3_interrupt'])(a0);
+var _sqlite3_is_interrupted = Module['_sqlite3_is_interrupted'] = (a0) => (_sqlite3_is_interrupted = Module['_sqlite3_is_interrupted'] = wasmExports['sqlite3_is_interrupted'])(a0);
+var _sqlite3_create_function_v2 = Module['_sqlite3_create_function_v2'] = (a0, a1, a2, a3, a4, a5, a6, a7, a8) => (_sqlite3_create_function_v2 = Module['_sqlite3_create_function_v2'] = wasmExports['sqlite3_create_function_v2'])(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+var _sqlite3_overload_function = Module['_sqlite3_overload_function'] = (a0, a1, a2) => (_sqlite3_overload_function = Module['_sqlite3_overload_function'] = wasmExports['sqlite3_overload_function'])(a0, a1, a2);
+var _sqlite3_trace_v2 = Module['_sqlite3_trace_v2'] = (a0, a1, a2, a3) => (_sqlite3_trace_v2 = Module['_sqlite3_trace_v2'] = wasmExports['sqlite3_trace_v2'])(a0, a1, a2, a3);
+var _sqlite3_commit_hook = Module['_sqlite3_commit_hook'] = (a0, a1, a2) => (_sqlite3_commit_hook = Module['_sqlite3_commit_hook'] = wasmExports['sqlite3_commit_hook'])(a0, a1, a2);
+var _sqlite3_update_hook = Module['_sqlite3_update_hook'] = (a0, a1, a2) => (_sqlite3_update_hook = Module['_sqlite3_update_hook'] = wasmExports['sqlite3_update_hook'])(a0, a1, a2);
+var _sqlite3_rollback_hook = Module['_sqlite3_rollback_hook'] = (a0, a1, a2) => (_sqlite3_rollback_hook = Module['_sqlite3_rollback_hook'] = wasmExports['sqlite3_rollback_hook'])(a0, a1, a2);
+var _sqlite3_error_offset = Module['_sqlite3_error_offset'] = (a0) => (_sqlite3_error_offset = Module['_sqlite3_error_offset'] = wasmExports['sqlite3_error_offset'])(a0);
+var _sqlite3_errcode = Module['_sqlite3_errcode'] = (a0) => (_sqlite3_errcode = Module['_sqlite3_errcode'] = wasmExports['sqlite3_errcode'])(a0);
+var _sqlite3_extended_errcode = Module['_sqlite3_extended_errcode'] = (a0) => (_sqlite3_extended_errcode = Module['_sqlite3_extended_errcode'] = wasmExports['sqlite3_extended_errcode'])(a0);
+var _sqlite3_errstr = Module['_sqlite3_errstr'] = (a0) => (_sqlite3_errstr = Module['_sqlite3_errstr'] = wasmExports['sqlite3_errstr'])(a0);
+var _sqlite3_limit = Module['_sqlite3_limit'] = (a0, a1, a2) => (_sqlite3_limit = Module['_sqlite3_limit'] = wasmExports['sqlite3_limit'])(a0, a1, a2);
+var _sqlite3_open = Module['_sqlite3_open'] = (a0, a1) => (_sqlite3_open = Module['_sqlite3_open'] = wasmExports['sqlite3_open'])(a0, a1);
+var _sqlite3_create_collation = Module['_sqlite3_create_collation'] = (a0, a1, a2, a3, a4) => (_sqlite3_create_collation = Module['_sqlite3_create_collation'] = wasmExports['sqlite3_create_collation'])(a0, a1, a2, a3, a4);
+var _sqlite3_create_collation_v2 = Module['_sqlite3_create_collation_v2'] = (a0, a1, a2, a3, a4, a5) => (_sqlite3_create_collation_v2 = Module['_sqlite3_create_collation_v2'] = wasmExports['sqlite3_create_collation_v2'])(a0, a1, a2, a3, a4, a5);
+var _sqlite3_collation_needed = Module['_sqlite3_collation_needed'] = (a0, a1, a2) => (_sqlite3_collation_needed = Module['_sqlite3_collation_needed'] = wasmExports['sqlite3_collation_needed'])(a0, a1, a2);
+var _sqlite3_get_autocommit = Module['_sqlite3_get_autocommit'] = (a0) => (_sqlite3_get_autocommit = Module['_sqlite3_get_autocommit'] = wasmExports['sqlite3_get_autocommit'])(a0);
+var _sqlite3_table_column_metadata = Module['_sqlite3_table_column_metadata'] = (a0, a1, a2, a3, a4, a5, a6, a7, a8) => (_sqlite3_table_column_metadata = Module['_sqlite3_table_column_metadata'] = wasmExports['sqlite3_table_column_metadata'])(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+var _sqlite3_extended_result_codes = Module['_sqlite3_extended_result_codes'] = (a0, a1) => (_sqlite3_extended_result_codes = Module['_sqlite3_extended_result_codes'] = wasmExports['sqlite3_extended_result_codes'])(a0, a1);
+var _sqlite3_uri_key = Module['_sqlite3_uri_key'] = (a0, a1) => (_sqlite3_uri_key = Module['_sqlite3_uri_key'] = wasmExports['sqlite3_uri_key'])(a0, a1);
+var _sqlite3_uri_int64 = Module['_sqlite3_uri_int64'] = (a0, a1, a2) => (_sqlite3_uri_int64 = Module['_sqlite3_uri_int64'] = wasmExports['sqlite3_uri_int64'])(a0, a1, a2);
+var _sqlite3_db_name = Module['_sqlite3_db_name'] = (a0, a1) => (_sqlite3_db_name = Module['_sqlite3_db_name'] = wasmExports['sqlite3_db_name'])(a0, a1);
+var _sqlite3_db_filename = Module['_sqlite3_db_filename'] = (a0, a1) => (_sqlite3_db_filename = Module['_sqlite3_db_filename'] = wasmExports['sqlite3_db_filename'])(a0, a1);
+var _sqlite3_db_readonly = Module['_sqlite3_db_readonly'] = (a0, a1) => (_sqlite3_db_readonly = Module['_sqlite3_db_readonly'] = wasmExports['sqlite3_db_readonly'])(a0, a1);
+var _sqlite3_compileoption_used = Module['_sqlite3_compileoption_used'] = (a0) => (_sqlite3_compileoption_used = Module['_sqlite3_compileoption_used'] = wasmExports['sqlite3_compileoption_used'])(a0);
+var _sqlite3_compileoption_get = Module['_sqlite3_compileoption_get'] = (a0) => (_sqlite3_compileoption_get = Module['_sqlite3_compileoption_get'] = wasmExports['sqlite3_compileoption_get'])(a0);
+var _sqlite3__wasm_pstack_ptr = Module['_sqlite3__wasm_pstack_ptr'] = () => (_sqlite3__wasm_pstack_ptr = Module['_sqlite3__wasm_pstack_ptr'] = wasmExports['sqlite3__wasm_pstack_ptr'])();
+var _sqlite3__wasm_pstack_restore = Module['_sqlite3__wasm_pstack_restore'] = (a0) => (_sqlite3__wasm_pstack_restore = Module['_sqlite3__wasm_pstack_restore'] = wasmExports['sqlite3__wasm_pstack_restore'])(a0);
+var _sqlite3__wasm_pstack_alloc = Module['_sqlite3__wasm_pstack_alloc'] = (a0) => (_sqlite3__wasm_pstack_alloc = Module['_sqlite3__wasm_pstack_alloc'] = wasmExports['sqlite3__wasm_pstack_alloc'])(a0);
+var _sqlite3__wasm_pstack_remaining = Module['_sqlite3__wasm_pstack_remaining'] = () => (_sqlite3__wasm_pstack_remaining = Module['_sqlite3__wasm_pstack_remaining'] = wasmExports['sqlite3__wasm_pstack_remaining'])();
+var _sqlite3__wasm_pstack_quota = Module['_sqlite3__wasm_pstack_quota'] = () => (_sqlite3__wasm_pstack_quota = Module['_sqlite3__wasm_pstack_quota'] = wasmExports['sqlite3__wasm_pstack_quota'])();
+var _sqlite3__wasm_db_error = Module['_sqlite3__wasm_db_error'] = (a0, a1, a2) => (_sqlite3__wasm_db_error = Module['_sqlite3__wasm_db_error'] = wasmExports['sqlite3__wasm_db_error'])(a0, a1, a2);
+var _sqlite3__wasm_test_struct = Module['_sqlite3__wasm_test_struct'] = (a0) => (_sqlite3__wasm_test_struct = Module['_sqlite3__wasm_test_struct'] = wasmExports['sqlite3__wasm_test_struct'])(a0);
+var _sqlite3__wasm_enum_json = Module['_sqlite3__wasm_enum_json'] = () => (_sqlite3__wasm_enum_json = Module['_sqlite3__wasm_enum_json'] = wasmExports['sqlite3__wasm_enum_json'])();
+var _sqlite3__wasm_vfs_unlink = Module['_sqlite3__wasm_vfs_unlink'] = (a0, a1) => (_sqlite3__wasm_vfs_unlink = Module['_sqlite3__wasm_vfs_unlink'] = wasmExports['sqlite3__wasm_vfs_unlink'])(a0, a1);
+var _sqlite3__wasm_db_vfs = Module['_sqlite3__wasm_db_vfs'] = (a0, a1) => (_sqlite3__wasm_db_vfs = Module['_sqlite3__wasm_db_vfs'] = wasmExports['sqlite3__wasm_db_vfs'])(a0, a1);
+var _sqlite3__wasm_db_reset = Module['_sqlite3__wasm_db_reset'] = (a0) => (_sqlite3__wasm_db_reset = Module['_sqlite3__wasm_db_reset'] = wasmExports['sqlite3__wasm_db_reset'])(a0);
+var _sqlite3__wasm_db_export_chunked = Module['_sqlite3__wasm_db_export_chunked'] = (a0, a1) => (_sqlite3__wasm_db_export_chunked = Module['_sqlite3__wasm_db_export_chunked'] = wasmExports['sqlite3__wasm_db_export_chunked'])(a0, a1);
+var _sqlite3__wasm_db_serialize = Module['_sqlite3__wasm_db_serialize'] = (a0, a1, a2, a3, a4) => (_sqlite3__wasm_db_serialize = Module['_sqlite3__wasm_db_serialize'] = wasmExports['sqlite3__wasm_db_serialize'])(a0, a1, a2, a3, a4);
+var _sqlite3__wasm_vfs_create_file = Module['_sqlite3__wasm_vfs_create_file'] = (a0, a1, a2, a3) => (_sqlite3__wasm_vfs_create_file = Module['_sqlite3__wasm_vfs_create_file'] = wasmExports['sqlite3__wasm_vfs_create_file'])(a0, a1, a2, a3);
+var _sqlite3__wasm_posix_create_file = Module['_sqlite3__wasm_posix_create_file'] = (a0, a1, a2) => (_sqlite3__wasm_posix_create_file = Module['_sqlite3__wasm_posix_create_file'] = wasmExports['sqlite3__wasm_posix_create_file'])(a0, a1, a2);
+var _sqlite3__wasm_kvvfsMakeKeyOnPstack = Module['_sqlite3__wasm_kvvfsMakeKeyOnPstack'] = (a0, a1) => (_sqlite3__wasm_kvvfsMakeKeyOnPstack = Module['_sqlite3__wasm_kvvfsMakeKeyOnPstack'] = wasmExports['sqlite3__wasm_kvvfsMakeKeyOnPstack'])(a0, a1);
+var _sqlite3__wasm_kvvfs_methods = Module['_sqlite3__wasm_kvvfs_methods'] = () => (_sqlite3__wasm_kvvfs_methods = Module['_sqlite3__wasm_kvvfs_methods'] = wasmExports['sqlite3__wasm_kvvfs_methods'])();
+var _sqlite3__wasm_vtab_config = Module['_sqlite3__wasm_vtab_config'] = (a0, a1, a2) => (_sqlite3__wasm_vtab_config = Module['_sqlite3__wasm_vtab_config'] = wasmExports['sqlite3__wasm_vtab_config'])(a0, a1, a2);
+var _sqlite3__wasm_db_config_ip = Module['_sqlite3__wasm_db_config_ip'] = (a0, a1, a2, a3) => (_sqlite3__wasm_db_config_ip = Module['_sqlite3__wasm_db_config_ip'] = wasmExports['sqlite3__wasm_db_config_ip'])(a0, a1, a2, a3);
+var _sqlite3__wasm_db_config_pii = Module['_sqlite3__wasm_db_config_pii'] = (a0, a1, a2, a3, a4) => (_sqlite3__wasm_db_config_pii = Module['_sqlite3__wasm_db_config_pii'] = wasmExports['sqlite3__wasm_db_config_pii'])(a0, a1, a2, a3, a4);
+var _sqlite3__wasm_db_config_s = Module['_sqlite3__wasm_db_config_s'] = (a0, a1, a2) => (_sqlite3__wasm_db_config_s = Module['_sqlite3__wasm_db_config_s'] = wasmExports['sqlite3__wasm_db_config_s'])(a0, a1, a2);
+var _sqlite3__wasm_config_i = Module['_sqlite3__wasm_config_i'] = (a0, a1) => (_sqlite3__wasm_config_i = Module['_sqlite3__wasm_config_i'] = wasmExports['sqlite3__wasm_config_i'])(a0, a1);
+var _sqlite3__wasm_config_ii = Module['_sqlite3__wasm_config_ii'] = (a0, a1, a2) => (_sqlite3__wasm_config_ii = Module['_sqlite3__wasm_config_ii'] = wasmExports['sqlite3__wasm_config_ii'])(a0, a1, a2);
+var _sqlite3__wasm_config_j = Module['_sqlite3__wasm_config_j'] = (a0, a1) => (_sqlite3__wasm_config_j = Module['_sqlite3__wasm_config_j'] = wasmExports['sqlite3__wasm_config_j'])(a0, a1);
+var _sqlite3__wasm_qfmt_token = Module['_sqlite3__wasm_qfmt_token'] = (a0, a1) => (_sqlite3__wasm_qfmt_token = Module['_sqlite3__wasm_qfmt_token'] = wasmExports['sqlite3__wasm_qfmt_token'])(a0, a1);
+var _sqlite3__wasm_init_wasmfs = Module['_sqlite3__wasm_init_wasmfs'] = (a0) => (_sqlite3__wasm_init_wasmfs = Module['_sqlite3__wasm_init_wasmfs'] = wasmExports['sqlite3__wasm_init_wasmfs'])(a0);
+var _sqlite3__wasm_test_intptr = Module['_sqlite3__wasm_test_intptr'] = (a0) => (_sqlite3__wasm_test_intptr = Module['_sqlite3__wasm_test_intptr'] = wasmExports['sqlite3__wasm_test_intptr'])(a0);
+var _sqlite3__wasm_test_voidptr = Module['_sqlite3__wasm_test_voidptr'] = (a0) => (_sqlite3__wasm_test_voidptr = Module['_sqlite3__wasm_test_voidptr'] = wasmExports['sqlite3__wasm_test_voidptr'])(a0);
+var _sqlite3__wasm_test_int64_max = Module['_sqlite3__wasm_test_int64_max'] = () => (_sqlite3__wasm_test_int64_max = Module['_sqlite3__wasm_test_int64_max'] = wasmExports['sqlite3__wasm_test_int64_max'])();
+var _sqlite3__wasm_test_int64_min = Module['_sqlite3__wasm_test_int64_min'] = () => (_sqlite3__wasm_test_int64_min = Module['_sqlite3__wasm_test_int64_min'] = wasmExports['sqlite3__wasm_test_int64_min'])();
+var _sqlite3__wasm_test_int64_times2 = Module['_sqlite3__wasm_test_int64_times2'] = (a0) => (_sqlite3__wasm_test_int64_times2 = Module['_sqlite3__wasm_test_int64_times2'] = wasmExports['sqlite3__wasm_test_int64_times2'])(a0);
+var _sqlite3__wasm_test_int64_minmax = Module['_sqlite3__wasm_test_int64_minmax'] = (a0, a1) => (_sqlite3__wasm_test_int64_minmax = Module['_sqlite3__wasm_test_int64_minmax'] = wasmExports['sqlite3__wasm_test_int64_minmax'])(a0, a1);
+var _sqlite3__wasm_test_int64ptr = Module['_sqlite3__wasm_test_int64ptr'] = (a0) => (_sqlite3__wasm_test_int64ptr = Module['_sqlite3__wasm_test_int64ptr'] = wasmExports['sqlite3__wasm_test_int64ptr'])(a0);
+var _sqlite3__wasm_test_stack_overflow = Module['_sqlite3__wasm_test_stack_overflow'] = (a0) => (_sqlite3__wasm_test_stack_overflow = Module['_sqlite3__wasm_test_stack_overflow'] = wasmExports['sqlite3__wasm_test_stack_overflow'])(a0);
+var _sqlite3__wasm_test_str_hello = Module['_sqlite3__wasm_test_str_hello'] = (a0) => (_sqlite3__wasm_test_str_hello = Module['_sqlite3__wasm_test_str_hello'] = wasmExports['sqlite3__wasm_test_str_hello'])(a0);
+var _sqlite3__wasm_SQLTester_strglob = Module['_sqlite3__wasm_SQLTester_strglob'] = (a0, a1) => (_sqlite3__wasm_SQLTester_strglob = Module['_sqlite3__wasm_SQLTester_strglob'] = wasmExports['sqlite3__wasm_SQLTester_strglob'])(a0, a1);
+var _realloc = Module['_realloc'] = (a0, a1) => (_realloc = Module['_realloc'] = wasmExports['realloc'])(a0, a1);
+var _emscripten_builtin_memalign = (a0, a1) => (_emscripten_builtin_memalign = wasmExports['emscripten_builtin_memalign'])(a0, a1);
+var __emscripten_stack_restore = (a0) => (__emscripten_stack_restore = wasmExports['_emscripten_stack_restore'])(a0);
+var __emscripten_stack_alloc = (a0) => (__emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc'])(a0);
+var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports['emscripten_stack_get_current'])();
+
+
+// include: postamble.js
+// === Auto-generated postamble setup entry stuff ===
+
+Module['wasmMemory'] = wasmMemory;
+
+
+var calledRun;
+
+dependenciesFulfilled = function runCaller() {
+ // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+ if (!calledRun) run();
+ if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+};
+
+function run() {
+
+ if (runDependencies > 0) {
+ return;
+ }
+
+ preRun();
+
+ // a preRun added a dependency, run will be called later
+ if (runDependencies > 0) {
+ return;
+ }
+
+ function doRun() {
+ // run may have just been called through dependencies being fulfilled just in this very frame,
+ // or while the async setStatus time below was happening
+ if (calledRun) return;
+ calledRun = true;
+ Module['calledRun'] = true;
+
+ if (ABORT) return;
+
+ initRuntime();
+
+ readyPromiseResolve(Module);
+ Module['onRuntimeInitialized']?.();
+
+ postRun();
+ }
+
+ if (Module['setStatus']) {
+ Module['setStatus']('Running...');
+ setTimeout(() => {
+ setTimeout(() => Module['setStatus'](''), 1);
+ doRun();
+ }, 1);
+ } else
+ {
+ doRun();
+ }
+}
+
+if (Module['preInit']) {
+ if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+ while (Module['preInit'].length > 0) {
+ Module['preInit'].pop()();
+ }
+}
+
+run();
+
+// end include: postamble.js
+
+// include: /usr/local/google/home/dlehmann/JetStream/sqlite3/sqlite-src-3470100/ext/wasm/bld/post-js.speedtest1-vanilla.js
+/* BEGIN FILE: api/post-js-header.js */
+/**
+ post-js-header.js is to be prepended to other code to create
+ post-js.js for use with Emscripten's --post-js flag. This code
+ requires that it be running in that context. The Emscripten
+ environment must have been set up already but it will not have
+ loaded its WASM when the code in this file is run. The function it
+ installs will be run after the WASM module is loaded, at which
+ point the sqlite3 JS API bits will get set up.
+*/
+if(!Module.postRun) Module.postRun = [];
+Module.postRun.push(function(Module/*the Emscripten-style module object*/){
+ 'use strict';
+ /* This function will contain at least the following:
+
+ - post-js-header.js (this file)
+ - sqlite3-api-prologue.js => Bootstrapping bits to attach the rest to
+ - common/whwasmutil.js => Replacements for much of Emscripten's glue
+ - jaccwaby/jaccwabyt.js => Jaccwabyt (C/JS struct binding)
+ - sqlite3-api-glue.js => glues previous parts together
+ - sqlite3-api-oo.js => SQLite3 OO API #1
+ - sqlite3-api-worker1.js => Worker-based API
+ - sqlite3-vfs-helper.c-pp.js => Utilities for VFS impls
+ - sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
+ - sqlite3-vfs-opfs.c-pp.js => OPFS VFS
+ - sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
+ - sqlite3-api-cleanup.js => final API cleanup
+ - post-js-footer.js => closes this postRun() function
+ */
+/* END FILE: api/post-js-header.js */
+/* BEGIN FILE: ./bld/sqlite3-api.c-pp.js */
+/* BEGIN FILE: ./bld/sqlite3-license-version.js */
+/*
+** LICENSE for the sqlite3 WebAssembly/JavaScript APIs.
+**
+** This bundle (typically released as sqlite3.js or sqlite3.mjs)
+** is an amalgamation of JavaScript source code from two projects:
+**
+** 1) https://emscripten.org: the Emscripten "glue code" is covered by
+** the terms of the MIT license and University of Illinois/NCSA
+** Open Source License, as described at:
+**
+** https://emscripten.org/docs/introducing_emscripten/emscripten_license.html
+**
+** 2) https://sqlite.org: all code and documentation labeled as being
+** from this source are released under the same terms as the sqlite3
+** C library:
+**
+** 2022-10-16
+**
+** The author disclaims copyright to this source code. In place of a
+** legal notice, here is a blessing:
+**
+** * May you do good and not evil.
+** * May you find forgiveness for yourself and forgive others.
+** * May you share freely, never taking more than you give.
+*/
+/*
+** This code was built from sqlite3 version...
+**
+** SQLITE_VERSION "3.47.1"
+** SQLITE_VERSION_NUMBER 3047001
+** SQLITE_SOURCE_ID "2024-11-25 12:07:48 b95d11e958643b969c47a8e5857f3793b9e69700b8f1469371386369a26e577e"
+**
+** Using the Emscripten SDK version 3.1.71.
+*/
+/* END FILE: ./bld/sqlite3-license-version.js */
+/* BEGIN FILE: api/sqlite3-api-prologue.js */
+/*
+ 2022-05-22
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file is intended to be combined at build-time with other
+ related code, most notably a header and footer which wraps this
+ whole file into an Emscripten Module.postRun() handler. The sqlite3
+ JS API has no hard requirements on Emscripten and does not expose
+ any Emscripten APIs to clients. It is structured such that its build
+ can be tweaked to include it in arbitrary WASM environments which
+ can supply the necessary underlying features (e.g. a POSIX file I/O
+ layer).
+
+ Main project home page: https://sqlite.org
+
+ Documentation home page: https://sqlite.org/wasm
+*/
+
+/**
+ sqlite3ApiBootstrap() is the only global symbol persistently
+ exposed by this API. It is intended to be called one time at the
+ end of the API amalgamation process, passed configuration details
+ for the current environment, and then optionally be removed from
+ the global object using `delete globalThis.sqlite3ApiBootstrap`.
+
+ This function is not intended for client-level use. It is intended
+ for use in creating bundles configured for specific WASM
+ environments.
+
+ This function expects a configuration object, intended to abstract
+ away details specific to any given WASM environment, primarily so
+ that it can be used without any direct dependency on
+ Emscripten. (Note the default values for the config object!) The
+ config object is only honored the first time this is
+ called. Subsequent calls ignore the argument and return the same
+ (configured) object which gets initialized by the first call. This
+ function will throw if any of the required config options are
+ missing.
+
+ The config object properties include:
+
+ - `exports`[^1]: the "exports" object for the current WASM
+ environment. In an Emscripten-based build, this should be set to
+ `Module['asm']`.
+
+ - `memory`[^1]: optional WebAssembly.Memory object, defaulting to
+ `exports.memory`. In Emscripten environments this should be set
+ to `Module.wasmMemory` if the build uses `-sIMPORTED_MEMORY`, or be
+ left undefined/falsy to default to `exports.memory` when using
+ WASM-exported memory.
+
+ - `bigIntEnabled`: true if BigInt support is enabled. Defaults to
+ true if `globalThis.BigInt64Array` is available, else false. Some APIs
+ will throw exceptions if called without BigInt support, as BigInt
+ is required for marshalling C-side int64 into and out of JS.
+ (Sidebar: it is technically possible to add int64 support via
+ marshalling of int32 pairs, but doing so is unduly invasive.)
+
+ - `allocExportName`: the name of the function, in `exports`, of the
+ `malloc(3)`-compatible routine for the WASM environment. Defaults
+ to `"sqlite3_malloc"`. Beware that using any allocator other than
+ sqlite3_malloc() may require care in certain client-side code
+ regarding which allocator is uses. Notably, sqlite3_deserialize()
+ and sqlite3_serialize() can only safely use memory from different
+ allocators under very specific conditions. The canonical builds
+ of this API guaranty that `sqlite3_malloc()` is the JS-side
+ allocator implementation.
+
+ - `deallocExportName`: the name of the function, in `exports`, of
+ the `free(3)`-compatible routine for the WASM
+ environment. Defaults to `"sqlite3_free"`.
+
+ - `reallocExportName`: the name of the function, in `exports`, of
+ the `realloc(3)`-compatible routine for the WASM
+ environment. Defaults to `"sqlite3_realloc"`.
+
+ - `debug`, `log`, `warn`, and `error` may be functions equivalent
+ to the like-named methods of the global `console` object. By
+ default, these map directly to their `console` counterparts, but
+ can be replaced with (e.g.) empty functions to squelch all such
+ output.
+
+ - `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the OPFS-backed
+ filesystem in WASMFS-capable builds.
+
+
+ [^1] = This property may optionally be a function, in which case
+ this function calls that function to fetch the value,
+ enabling delayed evaluation.
+
+ The returned object is the top-level sqlite3 namespace object.
+
+
+ Client code may optionally assign sqlite3ApiBootstrap.defaultConfig
+ an object-type value before calling sqlite3ApiBootstrap() (without
+ arguments) in order to tell that call to use this object as its
+ default config value. The intention of this is to provide
+ downstream clients with a reasonably flexible approach for plugging
+ in an environment-suitable configuration without having to define a
+ new global-scope symbol.
+
+ However, because clients who access this library via an
+ Emscripten-hosted module will not have an opportunity to call
+ sqlite3ApiBootstrap() themselves, nor to access it before it is
+ called, an alternative option for setting the configuration is to
+ define globalThis.sqlite3ApiConfig to an object. If it is set, it
+ is used instead of sqlite3ApiBootstrap.defaultConfig if
+ sqlite3ApiBootstrap() is called without arguments.
+
+ Both sqlite3ApiBootstrap.defaultConfig and
+ globalThis.sqlite3ApiConfig get deleted by sqlite3ApiBootstrap()
+ because any changes to them made after that point would have no
+ useful effect.
+*/
+'use strict';
+globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
+ apiConfig = (globalThis.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig)
+){
+ if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */
+ (sqlite3ApiBootstrap.sqlite3.config || console).warn(
+ "sqlite3ApiBootstrap() called multiple times.",
+ "Config and external initializers are ignored on calls after the first."
+ );
+ return sqlite3ApiBootstrap.sqlite3;
+ }
+ const config = Object.assign(Object.create(null),{
+ exports: undefined,
+ memory: undefined,
+ bigIntEnabled: (()=>{
+ if('undefined'!==typeof Module){
+ /* Emscripten module will contain HEAPU64 when built with
+ -sWASM_BIGINT=1, else it will not.
+
+ As of emsdk 3.1.55, when building in strict mode, HEAPxyz
+ are only available if _explicitly_ included in the exports,
+ else they are not. We do not (as of 2024-03-04) use -sSTRICT
+ for the canonical builds.
+ */
+ if( !!Module.HEAPU64 ) return true;
+ /* Else fall through and hope for the best. Nobody _really_
+ builds this without BigInt support, do they? */
+ }
+ return !!globalThis.BigInt64Array;
+ })(),
+ debug: console.debug.bind(console),
+ warn: console.warn.bind(console),
+ error: console.error.bind(console),
+ log: console.log.bind(console),
+ wasmfsOpfsDir: '/opfs',
+ /**
+ useStdAlloc is just for testing allocator discrepancies. The
+ docs guarantee that this is false in the canonical builds. For
+ 99% of purposes it doesn't matter which allocators we use, but
+ it becomes significant with, e.g., sqlite3_deserialize() and
+ certain wasm.xWrap.resultAdapter()s.
+ */
+ useStdAlloc: false
+ }, apiConfig || {});
+
+ Object.assign(config, {
+ allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc',
+ deallocExportName: config.useStdAlloc ? 'free' : 'sqlite3_free',
+ reallocExportName: config.useStdAlloc ? 'realloc' : 'sqlite3_realloc'
+ }, config);
+
+ [
+ // If any of these config options are functions, replace them with
+ // the result of calling that function...
+ 'exports', 'memory', 'wasmfsOpfsDir'
+ ].forEach((k)=>{
+ if('function' === typeof config[k]){
+ config[k] = config[k]();
+ }
+ });
+
+ /**
+ Eliminate any confusion about whether these config objects may
+ be used after library initialization by eliminating the outward-facing
+ objects...
+ */
+ delete globalThis.sqlite3ApiConfig;
+ delete sqlite3ApiBootstrap.defaultConfig;
+
+ /**
+ The main sqlite3 binding API gets installed into this object,
+ mimicking the C API as closely as we can. The numerous members
+ names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
+ possible, identically to the C-native counterparts, as documented at:
+
+ https://www.sqlite.org/c3ref/intro.html
+
+ A very few exceptions require an additional level of proxy
+ function or may otherwise require special attention in the WASM
+ environment, and all such cases are documented somewhere below
+ in this file or in sqlite3-api-glue.js. capi members which are
+ not documented are installed as 1-to-1 proxies for their
+ C-side counterparts.
+ */
+ const capi = Object.create(null);
+ /**
+ Holds state which are specific to the WASM-related
+ infrastructure and glue code.
+
+ Note that a number of members of this object are injected
+ dynamically after the api object is fully constructed, so
+ not all are documented in this file.
+ */
+ const wasm = Object.create(null);
+
+ /** Internal helper for SQLite3Error ctor. */
+ const __rcStr = (rc)=>{
+ return (capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc))
+ || ("Unknown result code #"+rc);
+ };
+
+ /** Internal helper for SQLite3Error ctor. */
+ const __isInt = (n)=>'number'===typeof n && n===(n | 0);
+
+ /**
+ An Error subclass specifically for reporting DB-level errors and
+ enabling clients to unambiguously identify such exceptions.
+ The C-level APIs never throw, but some of the higher-level
+ C-style APIs do and the object-oriented APIs use exceptions
+ exclusively to report errors.
+ */
+ class SQLite3Error extends Error {
+ /**
+ Constructs this object with a message depending on its arguments:
+
+ If its first argument is an integer, it is assumed to be
+ an SQLITE_... result code and it is passed to
+ sqlite3.capi.sqlite3_js_rc_str() to stringify it.
+
+ If called with exactly 2 arguments and the 2nd is an object,
+ that object is treated as the 2nd argument to the parent
+ constructor.
+
+ The exception's message is created by concatenating its
+ arguments with a space between each, except for the
+ two-args-with-an-object form and that the first argument will
+ get coerced to a string, as described above, if it's an
+ integer.
+
+ If passed an integer first argument, the error object's
+ `resultCode` member will be set to the given integer value,
+ else it will be set to capi.SQLITE_ERROR.
+ */
+ constructor(...args){
+ let rc;
+ if(args.length){
+ if(__isInt(args[0])){
+ rc = args[0];
+ if(1===args.length){
+ super(__rcStr(args[0]));
+ }else{
+ const rcStr = __rcStr(rc);
+ if('object'===typeof args[1]){
+ super(rcStr,args[1]);
+ }else{
+ args[0] = rcStr+':';
+ super(args.join(' '));
+ }
+ }
+ }else{
+ if(2===args.length && 'object'===typeof args[1]){
+ super(...args);
+ }else{
+ super(args.join(' '));
+ }
+ }
+ }
+ this.resultCode = rc || capi.SQLITE_ERROR;
+ this.name = 'SQLite3Error';
+ }
+ };
+
+ /**
+ Functionally equivalent to the SQLite3Error constructor but may
+ be used as part of an expression, e.g.:
+
+ ```
+ return someFunction(x) || SQLite3Error.toss(...);
+ ```
+ */
+ SQLite3Error.toss = (...args)=>{
+ throw new SQLite3Error(...args);
+ };
+ const toss3 = SQLite3Error.toss;
+
+ if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){
+ toss3("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
+ }
+
+ /**
+ Returns true if n is a 32-bit (signed) integer, else
+ false. This is used for determining when we need to switch to
+ double-type DB operations for integer values in order to keep
+ more precision.
+ */
+ const isInt32 = (n)=>{
+ return ('bigint'!==typeof n /*TypeError: can't convert BigInt to number*/)
+ && !!(n===(n|0) && n<=2147483647 && n>=-2147483648);
+ };
+ /**
+ Returns true if the given BigInt value is small enough to fit
+ into an int64 value, else false.
+ */
+ const bigIntFits64 = function f(b){
+ if(!f._max){
+ f._max = BigInt("0x7fffffffffffffff");
+ f._min = ~f._max;
+ }
+ return b >= f._min && b <= f._max;
+ };
+
+ /**
+ Returns true if the given BigInt value is small enough to fit
+ into an int32, else false.
+ */
+ const bigIntFits32 = (b)=>(b >= (-0x7fffffffn - 1n) && b <= 0x7fffffffn);
+
+ /**
+ Returns true if the given BigInt value is small enough to fit
+ into a double value without loss of precision, else false.
+ */
+ const bigIntFitsDouble = function f(b){
+ if(!f._min){
+ f._min = Number.MIN_SAFE_INTEGER;
+ f._max = Number.MAX_SAFE_INTEGER;
+ }
+ return b >= f._min && b <= f._max;
+ };
+
+ /** Returns v if v appears to be a TypedArray, else false. */
+ const isTypedArray = (v)=>{
+ return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false;
+ };
+
+
+ /** Internal helper to use in operations which need to distinguish
+ between TypedArrays which are backed by a SharedArrayBuffer
+ from those which are not. */
+ const __SAB = ('undefined'===typeof SharedArrayBuffer)
+ ? function(){} : SharedArrayBuffer;
+ /** Returns true if the given TypedArray object is backed by a
+ SharedArrayBuffer, else false. */
+ const isSharedTypedArray = (aTypedArray)=>(aTypedArray.buffer instanceof __SAB);
+
+ /**
+ Returns either aTypedArray.slice(begin,end) (if
+ aTypedArray.buffer is a SharedArrayBuffer) or
+ aTypedArray.subarray(begin,end) (if it's not).
+
+ This distinction is important for APIs which don't like to
+ work on SABs, e.g. TextDecoder, and possibly for our
+ own APIs which work on memory ranges which "might" be
+ modified by other threads while they're working.
+ */
+ const typedArrayPart = (aTypedArray, begin, end)=>{
+ return isSharedTypedArray(aTypedArray)
+ ? aTypedArray.slice(begin, end)
+ : aTypedArray.subarray(begin, end);
+ };
+
+ /**
+ Returns true if v appears to be one of our bind()-able TypedArray
+ types: Uint8Array or Int8Array or ArrayBuffer. Support for
+ TypedArrays with element sizes >1 is a potential TODO just
+ waiting on a use case to justify them. Until then, their `buffer`
+ property can be used to pass them as an ArrayBuffer. If it's not
+ a bindable array type, a falsy value is returned.
+ */
+ const isBindableTypedArray = (v)=>{
+ return v && (v instanceof Uint8Array
+ || v instanceof Int8Array
+ || v instanceof ArrayBuffer);
+ };
+
+ /**
+ Returns true if v appears to be one of the TypedArray types
+ which is legal for holding SQL code (as opposed to binary blobs).
+
+ Currently this is the same as isBindableTypedArray() but it
+ seems likely that we'll eventually want to add Uint32Array
+ and friends to the isBindableTypedArray() list but not to the
+ isSQLableTypedArray() list.
+ */
+ const isSQLableTypedArray = (v)=>{
+ return v && (v instanceof Uint8Array
+ || v instanceof Int8Array
+ || v instanceof ArrayBuffer);
+ };
+
+ /** Returns true if isBindableTypedArray(v) does, else throws with a message
+ that v is not a supported TypedArray value. */
+ const affirmBindableTypedArray = (v)=>{
+ return isBindableTypedArray(v)
+ || toss3("Value is not of a supported TypedArray type.");
+ };
+
+ const utf8Decoder = new TextDecoder('utf-8');
+
+ /**
+ Uses TextDecoder to decode the given half-open range of the
+ given TypedArray to a string. This differs from a simple
+ call to TextDecoder in that it accounts for whether the
+ first argument is backed by a SharedArrayBuffer or not,
+ and can work more efficiently if it's not (TextDecoder
+ refuses to act upon an SAB).
+ */
+ const typedArrayToString = function(typedArray, begin, end){
+ return utf8Decoder.decode(typedArrayPart(typedArray, begin,end));
+ };
+
+ /**
+ If v is-a Array, its join("") result is returned. If
+ isSQLableTypedArray(v) is true then typedArrayToString(v) is
+ returned. If it looks like a WASM pointer, wasm.cstrToJs(v) is
+ returned. Else v is returned as-is.
+ */
+ const flexibleString = function(v){
+ if(isSQLableTypedArray(v)){
+ return typedArrayToString(
+ (v instanceof ArrayBuffer) ? new Uint8Array(v) : v
+ );
+ }
+ else if(Array.isArray(v)) return v.join("");
+ else if(wasm.isPtr(v)) v = wasm.cstrToJs(v);
+ return v;
+ };
+
+ /**
+ An Error subclass specifically for reporting Wasm-level malloc()
+ failure and enabling clients to unambiguously identify such
+ exceptions.
+ */
+ class WasmAllocError extends Error {
+ /**
+ If called with 2 arguments and the 2nd one is an object, it
+ behaves like the Error constructor, else it concatenates all
+ arguments together with a single space between each to
+ construct an error message string. As a special case, if
+ called with no arguments then it uses a default error
+ message.
+ */
+ constructor(...args){
+ if(2===args.length && 'object'===typeof args[1]){
+ super(...args);
+ }else if(args.length){
+ super(args.join(' '));
+ }else{
+ super("Allocation failed.");
+ }
+ this.resultCode = capi.SQLITE_NOMEM;
+ this.name = 'WasmAllocError';
+ }
+ };
+ /**
+ Functionally equivalent to the WasmAllocError constructor but may
+ be used as part of an expression, e.g.:
+
+ ```
+ return someAllocatingFunction(x) || WasmAllocError.toss(...);
+ ```
+ */
+ WasmAllocError.toss = (...args)=>{
+ throw new WasmAllocError(...args);
+ };
+
+ Object.assign(capi, {
+ /**
+ sqlite3_bind_blob() works exactly like its C counterpart unless
+ its 3rd argument is one of:
+
+ - JS string: the 3rd argument is converted to a C string, the
+ 4th argument is ignored, and the C-string's length is used
+ in its place.
+
+ - Array: converted to a string as defined for "flexible
+ strings" and then it's treated as a JS string.
+
+ - Int8Array or Uint8Array: wasm.allocFromTypedArray() is used to
+ conver the memory to the WASM heap. If the 4th argument is
+ 0 or greater, it is used as-is, otherwise the array's byteLength
+ value is used. This is an exception to the C API's undefined
+ behavior for a negative 4th argument, but results are undefined
+ if the given 4th argument value is greater than the byteLength
+ of the input array.
+
+ - If it's an ArrayBuffer, it gets wrapped in a Uint8Array and
+ treated as that type.
+
+ In all of those cases, the final argument (destructor) is
+ ignored and capi.SQLITE_WASM_DEALLOC is assumed.
+
+ A 3rd argument of `null` is treated as if it were a WASM pointer
+ of 0.
+
+ If the 3rd argument is neither a WASM pointer nor one of the
+ above-described types, capi.SQLITE_MISUSE is returned.
+
+ The first argument may be either an `sqlite3_stmt*` WASM
+ pointer or an sqlite3.oo1.Stmt instance.
+
+ For consistency with the C API, it requires the same number of
+ arguments. It returns capi.SQLITE_MISUSE if passed any other
+ argument count.
+ */
+ sqlite3_bind_blob: undefined/*installed later*/,
+
+ /**
+ sqlite3_bind_text() works exactly like its C counterpart unless
+ its 3rd argument is one of:
+
+ - JS string: the 3rd argument is converted to a C string, the
+ 4th argument is ignored, and the C-string's length is used
+ in its place.
+
+ - Array: converted to a string as defined for "flexible
+ strings". The 4th argument is ignored and a value of -1
+ is assumed.
+
+ - Int8Array or Uint8Array: is assumed to contain UTF-8 text, is
+ converted to a string. The 4th argument is ignored, replaced
+ by the array's byteLength value.
+
+ - If it's an ArrayBuffer, it gets wrapped in a Uint8Array and
+ treated as that type.
+
+ In each of those cases, the final argument (text destructor) is
+ ignored and capi.SQLITE_WASM_DEALLOC is assumed.
+
+ A 3rd argument of `null` is treated as if it were a WASM pointer
+ of 0.
+
+ If the 3rd argument is neither a WASM pointer nor one of the
+ above-described types, capi.SQLITE_MISUSE is returned.
+
+ The first argument may be either an `sqlite3_stmt*` WASM
+ pointer or an sqlite3.oo1.Stmt instance.
+
+ For consistency with the C API, it requires the same number of
+ arguments. It returns capi.SQLITE_MISUSE if passed any other
+ argument count.
+
+ If client code needs to bind partial strings, it needs to
+ either parcel the string up before passing it in here or it
+ must pass in a WASM pointer for the 3rd argument and a valid
+ 4th-argument value, taking care not to pass a value which
+ truncates a multi-byte UTF-8 character. When passing
+ WASM-format strings, it is important that the final argument be
+ valid or unexpected content can result can result, or even a
+ crash if the application reads past the WASM heap bounds.
+ */
+ sqlite3_bind_text: undefined/*installed later*/,
+
+ /**
+ sqlite3_create_function_v2() differs from its native
+ counterpart only in the following ways:
+
+ 1) The fourth argument (`eTextRep`) argument must not specify
+ any encoding other than sqlite3.SQLITE_UTF8. The JS API does not
+ currently support any other encoding and likely never
+ will. This function does not replace that argument on its own
+ because it may contain other flags. As a special case, if
+ the bottom 4 bits of that argument are 0, SQLITE_UTF8 is
+ assumed.
+
+ 2) Any of the four final arguments may be either WASM pointers
+ (assumed to be function pointers) or JS Functions. In the
+ latter case, each gets bound to WASM using
+ sqlite3.capi.wasm.installFunction() and that wrapper is passed
+ on to the native implementation.
+
+ For consistency with the C API, it requires the same number of
+ arguments. It returns capi.SQLITE_MISUSE if passed any other
+ argument count.
+
+ The semantics of JS functions are:
+
+ xFunc: is passed `(pCtx, ...values)`. Its return value becomes
+ the new SQL function's result.
+
+ xStep: is passed `(pCtx, ...values)`. Its return value is
+ ignored.
+
+ xFinal: is passed `(pCtx)`. Its return value becomes the new
+ aggregate SQL function's result.
+
+ xDestroy: is passed `(void*)`. Its return value is ignored. The
+ pointer passed to it is the one from the 5th argument to
+ sqlite3_create_function_v2().
+
+ Note that:
+
+ - `pCtx` in the above descriptions is a `sqlite3_context*`. At
+ least 99 times out of a hundred, that initial argument will
+ be irrelevant for JS UDF bindings, but it needs to be there
+ so that the cases where it _is_ relevant, in particular with
+ window and aggregate functions, have full access to the
+ lower-level sqlite3 APIs.
+
+ - When wrapping JS functions, the remaining arguments are passd
+ to them as positional arguments, not as an array of
+ arguments, because that allows callback definitions to be
+ more JS-idiomatic than C-like. For example `(pCtx,a,b)=>a+b`
+ is more intuitive and legible than
+ `(pCtx,args)=>args[0]+args[1]`. For cases where an array of
+ arguments would be more convenient, the callbacks simply need
+ to be declared like `(pCtx,...args)=>{...}`, in which case
+ `args` will be an array.
+
+ - If a JS wrapper throws, it gets translated to
+ sqlite3_result_error() or sqlite3_result_error_nomem(),
+ depending on whether the exception is an
+ sqlite3.WasmAllocError object or not.
+
+ - When passing on WASM function pointers, arguments are _not_
+ converted or reformulated. They are passed on as-is in raw
+ pointer form using their native C signatures. Only JS
+ functions passed in to this routine, and thus wrapped by this
+ routine, get automatic conversions of arguments and result
+ values. The routines which perform those conversions are
+ exposed for client-side use as
+ sqlite3_create_function_v2.convertUdfArgs() and
+ sqlite3_create_function_v2.setUdfResult(). sqlite3_create_function()
+ and sqlite3_create_window_function() have those same methods.
+
+ For xFunc(), xStep(), and xFinal():
+
+ - When called from SQL, arguments to the UDF, and its result,
+ will be converted between JS and SQL with as much fidelity as
+ is feasible, triggering an exception if a type conversion
+ cannot be determined. Some freedom is afforded to numeric
+ conversions due to friction between the JS and C worlds:
+ integers which are larger than 32 bits may be treated as
+ doubles or BigInts.
+
+ If any JS-side bound functions throw, those exceptions are
+ intercepted and converted to database-side errors with the
+ exception of xDestroy(): any exception from it is ignored,
+ possibly generating a console.error() message. Destructors
+ must not throw.
+
+ Once installed, there is currently no way to uninstall the
+ automatically-converted WASM-bound JS functions from WASM. They
+ can be uninstalled from the database as documented in the C
+ API, but this wrapper currently has no infrastructure in place
+ to also free the WASM-bound JS wrappers, effectively resulting
+ in a memory leak if the client uninstalls the UDF. Improving that
+ is a potential TODO, but removing client-installed UDFs is rare
+ in practice. If this factor is relevant for a given client,
+ they can create WASM-bound JS functions themselves, hold on to their
+ pointers, and pass the pointers in to here. Later on, they can
+ free those pointers (using `wasm.uninstallFunction()` or
+ equivalent).
+
+ C reference: https://www.sqlite.org/c3ref/create_function.html
+
+ Maintenance reminder: the ability to add new
+ WASM-accessible functions to the runtime requires that the
+ WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH`
+ flag.
+ */
+ sqlite3_create_function_v2: (
+ pDb, funcName, nArg, eTextRep, pApp,
+ xFunc, xStep, xFinal, xDestroy
+ )=>{/*installed later*/},
+ /**
+ Equivalent to passing the same arguments to
+ sqlite3_create_function_v2(), with 0 as the final argument.
+ */
+ sqlite3_create_function: (
+ pDb, funcName, nArg, eTextRep, pApp,
+ xFunc, xStep, xFinal
+ )=>{/*installed later*/},
+ /**
+ The sqlite3_create_window_function() JS wrapper differs from
+ its native implementation in the exact same way that
+ sqlite3_create_function_v2() does. The additional function,
+ xInverse(), is treated identically to xStep() by the wrapping
+ layer.
+ */
+ sqlite3_create_window_function: (
+ pDb, funcName, nArg, eTextRep, pApp,
+ xStep, xFinal, xValue, xInverse, xDestroy
+ )=>{/*installed later*/},
+ /**
+ The sqlite3_prepare_v3() binding handles two different uses
+ with differing JS/WASM semantics:
+
+ 1) sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt , null)
+
+ 2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer)
+
+ Note that the SQL length argument (the 3rd argument) must, for
+ usage (1), always be negative because it must be a byte length
+ and that value is expensive to calculate from JS (where only
+ the character length of strings is readily available). It is
+ retained in this API's interface for code/documentation
+ compatibility reasons but is currently _always_ ignored. With
+ usage (2), the 3rd argument is used as-is but is is still
+ critical that the C-style input string (2nd argument) be
+ terminated with a 0 byte.
+
+ In usage (1), the 2nd argument must be of type string,
+ Uint8Array, Int8Array, or ArrayBuffer (all of which are assumed
+ to hold SQL). If it is, this function assumes case (1) and
+ calls the underyling C function with the equivalent of:
+
+ (pDb, sqlAsString, -1, prepFlags, ppStmt, null)
+
+ The `pzTail` argument is ignored in this case because its
+ result is meaningless when a string-type value is passed
+ through: the string goes through another level of internal
+ conversion for WASM's sake and the result pointer would refer
+ to that transient conversion's memory, not the passed-in
+ string.
+
+ If the sql argument is not a string, it must be a _pointer_ to
+ a NUL-terminated string which was allocated in the WASM memory
+ (e.g. using capi.wasm.alloc() or equivalent). In that case,
+ the final argument may be 0/null/undefined or must be a pointer
+ to which the "tail" of the compiled SQL is written, as
+ documented for the C-side sqlite3_prepare_v3(). In case (2),
+ the underlying C function is called with the equivalent of:
+
+ (pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail)
+
+ It returns its result and compiled statement as documented in
+ the C API. Fetching the output pointers (5th and 6th
+ parameters) requires using `capi.wasm.peek()` (or
+ equivalent) and the `pzTail` will point to an address relative to
+ the `sqlAsPointer` value.
+
+ If passed an invalid 2nd argument type, this function will
+ return SQLITE_MISUSE and sqlite3_errmsg() will contain a string
+ describing the problem.
+
+ Side-note: if given an empty string, or one which contains only
+ comments or an empty SQL expression, 0 is returned but the result
+ output pointer will be NULL.
+ */
+ sqlite3_prepare_v3: (dbPtr, sql, sqlByteLen, prepFlags,
+ stmtPtrPtr, strPtrPtr)=>{}/*installed later*/,
+
+ /**
+ Equivalent to calling sqlite3_prapare_v3() with 0 as its 4th argument.
+ */
+ sqlite3_prepare_v2: (dbPtr, sql, sqlByteLen,
+ stmtPtrPtr,strPtrPtr)=>{}/*installed later*/,
+
+ /**
+ This binding enables the callback argument to be a JavaScript.
+
+ If the callback is a function, then for the duration of the
+ sqlite3_exec() call, it installs a WASM-bound function which
+ acts as a proxy for the given callback. That proxy will also
+ perform a conversion of the callback's arguments from
+ `(char**)` to JS arrays of strings. However, for API
+ consistency's sake it will still honor the C-level callback
+ parameter order and will call it like:
+
+ `callback(pVoid, colCount, listOfValues, listOfColNames)`
+
+ If the callback is not a JS function then this binding performs
+ no translation of the callback, but the sql argument is still
+ converted to a WASM string for the call using the
+ "string:flexible" argument converter.
+ */
+ sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/,
+
+ /**
+ If passed a single argument which appears to be a byte-oriented
+ TypedArray (Int8Array or Uint8Array), this function treats that
+ TypedArray as an output target, fetches `theArray.byteLength`
+ bytes of randomness, and populates the whole array with it. As
+ a special case, if the array's length is 0, this function
+ behaves as if it were passed (0,0). When called this way, it
+ returns its argument, else it returns the `undefined` value.
+
+ If called with any other arguments, they are passed on as-is
+ to the C API. Results are undefined if passed any incompatible
+ values.
+ */
+ sqlite3_randomness: (n, outPtr)=>{/*installed later*/},
+ }/*capi*/);
+
+ /**
+ Various internal-use utilities are added here as needed. They
+ are bound to an object only so that we have access to them in
+ the differently-scoped steps of the API bootstrapping
+ process. At the end of the API setup process, this object gets
+ removed. These are NOT part of the public API.
+ */
+ const util = {
+ affirmBindableTypedArray, flexibleString,
+ bigIntFits32, bigIntFits64, bigIntFitsDouble,
+ isBindableTypedArray,
+ isInt32, isSQLableTypedArray, isTypedArray,
+ typedArrayToString,
+ isUIThread: ()=>(globalThis.window===globalThis && !!globalThis.document),
+ // is this true for ESM?: 'undefined'===typeof WorkerGlobalScope
+ isSharedTypedArray,
+ toss: function(...args){throw new Error(args.join(' '))},
+ toss3,
+ typedArrayPart,
+ /**
+ Given a byte array or ArrayBuffer, this function throws if the
+ lead bytes of that buffer do not hold a SQLite3 database header,
+ else it returns without side effects.
+
+ Added in 3.44.
+ */
+ affirmDbHeader: function(bytes){
+ if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
+ const header = "SQLite format 3";
+ if( header.length > bytes.byteLength ){
+ toss3("Input does not contain an SQLite3 database header.");
+ }
+ for(let i = 0; i < header.length; ++i){
+ if( header.charCodeAt(i) !== bytes[i] ){
+ toss3("Input does not contain an SQLite3 database header.");
+ }
+ }
+ },
+ /**
+ Given a byte array or ArrayBuffer, this function throws if the
+ database does not, at a cursory glance, appear to be an SQLite3
+ database. It only examines the size and header, but further
+ checks may be added in the future.
+
+ Added in 3.44.
+ */
+ affirmIsDb: function(bytes){
+ if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
+ const n = bytes.byteLength;
+ if(n<512 || n%512!==0) {
+ toss3("Byte array size",n,"is invalid for an SQLite3 db.");
+ }
+ util.affirmDbHeader(bytes);
+ }
+ }/*util*/;
+
+ Object.assign(wasm, {
+ /**
+ Emscripten APIs have a deep-seated assumption that all pointers
+ are 32 bits. We'll remain optimistic that that won't always be
+ the case and will use this constant in places where we might
+ otherwise use a hard-coded 4.
+ */
+ ptrSizeof: config.wasmPtrSizeof || 4,
+ /**
+ The WASM IR (Intermediate Representation) value for
+ pointer-type values. It MUST refer to a value type of the
+ size described by this.ptrSizeof.
+ */
+ ptrIR: config.wasmPtrIR || "i32",
+ /**
+ True if BigInt support was enabled via (e.g.) the
+ Emscripten -sWASM_BIGINT flag, else false. When
+ enabled, certain 64-bit sqlite3 APIs are enabled which
+ are not otherwise enabled due to JS/WASM int64
+ impedence mismatches.
+ */
+ bigIntEnabled: !!config.bigIntEnabled,
+ /**
+ The symbols exported by the WASM environment.
+ */
+ exports: config.exports
+ || toss3("Missing API config.exports (WASM module exports)."),
+
+ /**
+ When Emscripten compiles with `-sIMPORTED_MEMORY`, it
+ initalizes the heap and imports it into wasm, as opposed to
+ the other way around. In this case, the memory is not
+ available via this.exports.memory.
+ */
+ memory: config.memory || config.exports['memory']
+ || toss3("API config object requires a WebAssembly.Memory object",
+ "in either config.exports.memory (exported)",
+ "or config.memory (imported)."),
+
+ /**
+ The API's primary point of access to the WASM-side memory
+ allocator. Works like sqlite3_malloc() but throws a
+ WasmAllocError if allocation fails. It is important that any
+ code which might pass through the sqlite3 C API NOT throw and
+ must instead return SQLITE_NOMEM (or equivalent, depending on
+ the context).
+
+ Very few cases in the sqlite3 JS APIs can result in
+ client-defined functions propagating exceptions via the C-style
+ API. Most notably, this applies to WASM-bound JS functions
+ which are created directly by clients and passed on _as WASM
+ function pointers_ to functions such as
+ sqlite3_create_function_v2(). Such bindings created
+ transparently by this API will automatically use wrappers which
+ catch exceptions and convert them to appropriate error codes.
+
+ For cases where non-throwing allocation is required, use
+ this.alloc.impl(), which is direct binding of the
+ underlying C-level allocator.
+
+ Design note: this function is not named "malloc" primarily
+ because Emscripten uses that name and we wanted to avoid any
+ confusion early on in this code's development, when it still
+ had close ties to Emscripten's glue code.
+ */
+ alloc: undefined/*installed later*/,
+
+ /**
+ Rarely necessary in JS code, this routine works like
+ sqlite3_realloc(M,N), where M is either NULL or a pointer
+ obtained from this function or this.alloc() and N is the number
+ of bytes to reallocate the block to. Returns a pointer to the
+ reallocated block or 0 if allocation fails.
+
+ If M is NULL and N is positive, this behaves like
+ this.alloc(N). If N is 0, it behaves like this.dealloc().
+ Results are undefined if N is negative (sqlite3_realloc()
+ treats that as 0, but if this code is built with a different
+ allocator it may misbehave with negative values).
+
+ Like this.alloc.impl(), this.realloc.impl() is a direct binding
+ to the underlying realloc() implementation which does not throw
+ exceptions, instead returning 0 on allocation error.
+ */
+ realloc: undefined/*installed later*/,
+
+ /**
+ The API's primary point of access to the WASM-side memory
+ deallocator. Works like sqlite3_free().
+
+ Design note: this function is not named "free" for the same
+ reason that this.alloc() is not called this.malloc().
+ */
+ dealloc: undefined/*installed later*/
+
+ /* Many more wasm-related APIs get installed later on. */
+ }/*wasm*/);
+
+ /**
+ wasm.alloc()'s srcTypedArray.byteLength bytes,
+ populates them with the values from the source
+ TypedArray, and returns the pointer to that memory. The
+ returned pointer must eventually be passed to
+ wasm.dealloc() to clean it up.
+
+ The argument may be a Uint8Array, Int8Array, or ArrayBuffer,
+ and it throws if passed any other type.
+
+ As a special case, to avoid further special cases where
+ this is used, if srcTypedArray.byteLength is 0, it
+ allocates a single byte and sets it to the value
+ 0. Even in such cases, calls must behave as if the
+ allocated memory has exactly srcTypedArray.byteLength
+ bytes.
+ */
+ wasm.allocFromTypedArray = function(srcTypedArray){
+ if(srcTypedArray instanceof ArrayBuffer){
+ srcTypedArray = new Uint8Array(srcTypedArray);
+ }
+ affirmBindableTypedArray(srcTypedArray);
+ const pRet = wasm.alloc(srcTypedArray.byteLength || 1);
+ wasm.heapForSize(srcTypedArray.constructor).set(
+ srcTypedArray.byteLength ? srcTypedArray : [0], pRet
+ );
+ return pRet;
+ };
+
+ {
+ // Set up allocators...
+ const keyAlloc = config.allocExportName,
+ keyDealloc = config.deallocExportName,
+ keyRealloc = config.reallocExportName;
+ for(const key of [keyAlloc, keyDealloc, keyRealloc]){
+ const f = wasm.exports[key];
+ if(!(f instanceof Function)) toss3("Missing required exports[",key,"] function.");
+ }
+
+ wasm.alloc = function f(n){
+ return f.impl(n) || WasmAllocError.toss("Failed to allocate",n," bytes.");
+ };
+ wasm.alloc.impl = wasm.exports[keyAlloc];
+ wasm.realloc = function f(m,n){
+ const m2 = f.impl(m,n);
+ return n ? (m2 || WasmAllocError.toss("Failed to reallocate",n," bytes.")) : 0;
+ };
+ wasm.realloc.impl = wasm.exports[keyRealloc];
+ wasm.dealloc = wasm.exports[keyDealloc];
+ }
+
+ /**
+ Reports info about compile-time options using
+ sqlite3_compileoption_get() and sqlite3_compileoption_used(). It
+ has several distinct uses:
+
+ If optName is an array then it is expected to be a list of
+ compilation options and this function returns an object
+ which maps each such option to true or false, indicating
+ whether or not the given option was included in this
+ build. That object is returned.
+
+ If optName is an object, its keys are expected to be compilation
+ options and this function sets each entry to true or false,
+ indicating whether the compilation option was used or not. That
+ object is returned.
+
+ If passed no arguments then it returns an object mapping
+ all known compilation options to their compile-time values,
+ or boolean true if they are defined with no value. This
+ result, which is relatively expensive to compute, is cached
+ and returned for future no-argument calls.
+
+ In all other cases it returns true if the given option was
+ active when when compiling the sqlite3 module, else false.
+
+ Compile-time option names may optionally include their
+ "SQLITE_" prefix. When it returns an object of all options,
+ the prefix is elided.
+ */
+ wasm.compileOptionUsed = function f(optName){
+ if(!arguments.length){
+ if(f._result) return f._result;
+ else if(!f._opt){
+ f._rx = /^([^=]+)=(.+)/;
+ f._rxInt = /^-?\d+$/;
+ f._opt = function(opt, rv){
+ const m = f._rx.exec(opt);
+ rv[0] = (m ? m[1] : opt);
+ rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true;
+ };
+ }
+ const rc = {}, ov = [0,0];
+ let i = 0, k;
+ while((k = capi.sqlite3_compileoption_get(i++))){
+ f._opt(k,ov);
+ rc[ov[0]] = ov[1];
+ }
+ return f._result = rc;
+ }else if(Array.isArray(optName)){
+ const rc = {};
+ optName.forEach((v)=>{
+ rc[v] = capi.sqlite3_compileoption_used(v);
+ });
+ return rc;
+ }else if('object' === typeof optName){
+ Object.keys(optName).forEach((k)=> {
+ optName[k] = capi.sqlite3_compileoption_used(k);
+ });
+ return optName;
+ }
+ return (
+ 'string'===typeof optName
+ ) ? !!capi.sqlite3_compileoption_used(optName) : false;
+ }/*compileOptionUsed()*/;
+
+ /**
+ sqlite3.wasm.pstack (pseudo-stack) holds a special-case
+ stack-style allocator intended only for use with _small_ data of
+ not more than (in total) a few kb in size, managed as if it were
+ stack-based.
+
+ It has only a single intended usage:
+
+ ```
+ const stackPos = pstack.pointer;
+ try{
+ const ptr = pstack.alloc(8);
+ // ==> pstack.pointer === ptr
+ const otherPtr = pstack.alloc(8);
+ // ==> pstack.pointer === otherPtr
+ ...
+ }finally{
+ pstack.restore(stackPos);
+ // ==> pstack.pointer === stackPos
+ }
+ ```
+
+ This allocator is much faster than a general-purpose one but is
+ limited to usage patterns like the one shown above.
+
+ It operates from a static range of memory which lives outside of
+ space managed by Emscripten's stack-management, so does not
+ collide with Emscripten-provided stack allocation APIs. The
+ memory lives in the WASM heap and can be used with routines such
+ as wasm.poke() and wasm.heap8u().slice().
+ */
+ wasm.pstack = Object.assign(Object.create(null),{
+ /**
+ Sets the current pstack position to the given pointer. Results
+ are undefined if the passed-in value did not come from
+ this.pointer.
+ */
+ restore: wasm.exports.sqlite3__wasm_pstack_restore,
+ /**
+ Attempts to allocate the given number of bytes from the
+ pstack. On success, it zeroes out a block of memory of the
+ given size, adjusts the pstack pointer, and returns a pointer
+ to the memory. On error, throws a WasmAllocError. The
+ memory must eventually be released using restore().
+
+ If n is a string, it must be a WASM "IR" value in the set
+ accepted by wasm.sizeofIR(), which is mapped to the size of
+ that data type. If passed a string not in that set, it throws a
+ WasmAllocError.
+
+ This method always adjusts the given value to be a multiple
+ of 8 bytes because failing to do so can lead to incorrect
+ results when reading and writing 64-bit values from/to the WASM
+ heap. Similarly, the returned address is always 8-byte aligned.
+ */
+ alloc: function(n){
+ if('string'===typeof n && !(n = wasm.sizeofIR(n))){
+ WasmAllocError.toss("Invalid value for pstack.alloc(",arguments[0],")");
+ }
+ return wasm.exports.sqlite3__wasm_pstack_alloc(n)
+ || WasmAllocError.toss("Could not allocate",n,
+ "bytes from the pstack.");
+ },
+ /**
+ alloc()'s n chunks, each sz bytes, as a single memory block and
+ returns the addresses as an array of n element, each holding
+ the address of one chunk.
+
+ sz may optionally be an IR string accepted by wasm.sizeofIR().
+
+ Throws a WasmAllocError if allocation fails.
+
+ Example:
+
+ ```
+ const [p1, p2, p3] = wasm.pstack.allocChunks(3,4);
+ ```
+ */
+ allocChunks: function(n,sz){
+ if('string'===typeof sz && !(sz = wasm.sizeofIR(sz))){
+ WasmAllocError.toss("Invalid size value for allocChunks(",arguments[1],")");
+ }
+ const mem = wasm.pstack.alloc(n * sz);
+ const rc = [];
+ let i = 0, offset = 0;
+ for(; i < n; ++i, offset += sz) rc.push(mem + offset);
+ return rc;
+ },
+ /**
+ A convenience wrapper for allocChunks() which sizes each chunk
+ as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if
+ safePtrSize is falsy).
+
+ How it returns its result differs depending on its first
+ argument: if it's 1, it returns a single pointer value. If it's
+ more than 1, it returns the same as allocChunks().
+
+ When a returned pointers will refer to a 64-bit value, e.g. a
+ double or int64, and that value must be written or fetched,
+ e.g. using wasm.poke() or wasm.peek(), it is
+ important that the pointer in question be aligned to an 8-byte
+ boundary or else it will not be fetched or written properly and
+ will corrupt or read neighboring memory.
+
+ However, when all pointers involved point to "small" data, it
+ is safe to pass a falsy value to save a tiny bit of memory.
+ */
+ allocPtr: (n=1,safePtrSize=true)=>{
+ return 1===n
+ ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof)
+ : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof);
+ },
+
+ /**
+ Records the current pstack position, calls the given function,
+ passing it the sqlite3 object, then restores the pstack
+ regardless of whether the function throws. Returns the result
+ of the call or propagates an exception on error.
+
+ Added in 3.44.
+ */
+ call: function(f){
+ const stackPos = wasm.pstack.pointer;
+ try{ return f(sqlite3) } finally{
+ wasm.pstack.restore(stackPos);
+ }
+ }
+
+ })/*wasm.pstack*/;
+ Object.defineProperties(wasm.pstack, {
+ /**
+ sqlite3.wasm.pstack.pointer resolves to the current pstack
+ position pointer. This value is intended _only_ to be saved
+ for passing to restore(). Writing to this memory, without
+ first reserving it via wasm.pstack.alloc() and friends, leads
+ to undefined results.
+ */
+ pointer: {
+ configurable: false, iterable: true, writeable: false,
+ get: wasm.exports.sqlite3__wasm_pstack_ptr
+ //Whether or not a setter as an alternative to restore() is
+ //clearer or would just lead to confusion is unclear.
+ //set: wasm.exports.sqlite3__wasm_pstack_restore
+ },
+ /**
+ sqlite3.wasm.pstack.quota to the total number of bytes
+ available in the pstack, including any space which is currently
+ allocated. This value is a compile-time constant.
+ */
+ quota: {
+ configurable: false, iterable: true, writeable: false,
+ get: wasm.exports.sqlite3__wasm_pstack_quota
+ },
+ /**
+ sqlite3.wasm.pstack.remaining resolves to the amount of space
+ remaining in the pstack.
+ */
+ remaining: {
+ configurable: false, iterable: true, writeable: false,
+ get: wasm.exports.sqlite3__wasm_pstack_remaining
+ }
+ })/*wasm.pstack properties*/;
+
+ capi.sqlite3_randomness = (...args)=>{
+ if(1===args.length && util.isTypedArray(args[0])
+ && 1===args[0].BYTES_PER_ELEMENT){
+ const ta = args[0];
+ if(0===ta.byteLength){
+ wasm.exports.sqlite3_randomness(0,0);
+ return ta;
+ }
+ const stack = wasm.pstack.pointer;
+ try {
+ let n = ta.byteLength, offset = 0;
+ const r = wasm.exports.sqlite3_randomness;
+ const heap = wasm.heap8u();
+ const nAlloc = n < 512 ? n : 512;
+ const ptr = wasm.pstack.alloc(nAlloc);
+ do{
+ const j = (n>nAlloc ? nAlloc : n);
+ r(j, ptr);
+ ta.set(typedArrayPart(heap, ptr, ptr+j), offset);
+ n -= j;
+ offset += j;
+ } while(n > 0);
+ }catch(e){
+ console.error("Highly unexpected (and ignored!) "+
+ "exception in sqlite3_randomness():",e);
+ }finally{
+ wasm.pstack.restore(stack);
+ }
+ return ta;
+ }
+ wasm.exports.sqlite3_randomness(...args);
+ };
+
+ /** State for sqlite3_wasmfs_opfs_dir(). */
+ let __wasmfsOpfsDir = undefined;
+ /**
+ If the wasm environment has a WASMFS/OPFS-backed persistent
+ storage directory, its path is returned by this function. If it
+ does not then it returns "" (noting that "" is a falsy value).
+
+ The first time this is called, this function inspects the current
+ environment to determine whether persistence support is available
+ and, if it is, enables it (if needed). After the first call it
+ always returns the cached result.
+
+ If the returned string is not empty, any files stored under the
+ given path (recursively) are housed in OPFS storage. If the
+ returned string is empty, this particular persistent storage
+ option is not available on the client.
+
+ Though the mount point name returned by this function is intended
+ to remain stable, clients should not hard-coded it
+ anywhere. Always call this function to get the path.
+
+ Note that this function is a no-op in most builds of this
+ library, as the WASMFS capability requires a custom
+ build.
+ */
+ capi.sqlite3_wasmfs_opfs_dir = function(){
+ if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir;
+ // If we have no OPFS, there is no persistent dir
+ const pdir = config.wasmfsOpfsDir;
+ if(!pdir
+ || !globalThis.FileSystemHandle
+ || !globalThis.FileSystemDirectoryHandle
+ || !globalThis.FileSystemFileHandle){
+ return __wasmfsOpfsDir = "";
+ }
+ try{
+ if(pdir && 0===wasm.xCallWrapped(
+ 'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir
+ )){
+ return __wasmfsOpfsDir = pdir;
+ }else{
+ return __wasmfsOpfsDir = "";
+ }
+ }catch(e){
+ // sqlite3__wasm_init_wasmfs() is not available
+ return __wasmfsOpfsDir = "";
+ }
+ };
+
+ /**
+ Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
+ non-empty string and the given name starts with (that string +
+ '/'), else returns false.
+ */
+ capi.sqlite3_wasmfs_filename_is_persistent = function(name){
+ const p = capi.sqlite3_wasmfs_opfs_dir();
+ return (p && name) ? name.startsWith(p+'/') : false;
+ };
+
+ /**
+ Given an `sqlite3*`, an sqlite3_vfs name, and an optional db name
+ (defaulting to "main"), returns a truthy value (see below) if
+ that db uses that VFS, else returns false. If pDb is falsy then
+ the 3rd argument is ignored and this function returns a truthy
+ value if the default VFS name matches that of the 2nd
+ argument. Results are undefined if pDb is truthy but refers to an
+ invalid pointer. The 3rd argument specifies the database name of
+ the given database connection to check, defaulting to the main
+ db.
+
+ The 2nd and 3rd arguments may either be a JS string or a WASM
+ C-string. If the 2nd argument is a NULL WASM pointer, the default
+ VFS is assumed. If the 3rd is a NULL WASM pointer, "main" is
+ assumed.
+
+ The truthy value it returns is a pointer to the `sqlite3_vfs`
+ object.
+
+ To permit safe use of this function from APIs which may be called
+ via the C stack (like SQL UDFs), this function does not throw: if
+ bad arguments cause a conversion error when passing into
+ wasm-space, false is returned.
+ */
+ capi.sqlite3_js_db_uses_vfs = function(pDb,vfsName,dbName=0){
+ try{
+ const pK = capi.sqlite3_vfs_find(vfsName);
+ if(!pK) return false;
+ else if(!pDb){
+ return pK===capi.sqlite3_vfs_find(0) ? pK : false;
+ }else{
+ return pK===capi.sqlite3_js_db_vfs(pDb,dbName) ? pK : false;
+ }
+ }catch(e){
+ /* Ignore - probably bad args to a wasm-bound function. */
+ return false;
+ }
+ };
+
+ /**
+ Returns an array of the names of all currently-registered sqlite3
+ VFSes.
+ */
+ capi.sqlite3_js_vfs_list = function(){
+ const rc = [];
+ let pVfs = capi.sqlite3_vfs_find(0);
+ while(pVfs){
+ const oVfs = new capi.sqlite3_vfs(pVfs);
+ rc.push(wasm.cstrToJs(oVfs.$zName));
+ pVfs = oVfs.$pNext;
+ oVfs.dispose();
+ }
+ return rc;
+ };
+
+ /**
+ A convenience wrapper around sqlite3_serialize() which serializes
+ the given `sqlite3*` pointer to a Uint8Array. The first argument
+ may be either an `sqlite3*` or an sqlite3.oo1.DB instance.
+
+ On success it returns a Uint8Array. If the schema is empty, an
+ empty array is returned.
+
+ `schema` is the schema to serialize. It may be a WASM C-string
+ pointer or a JS string. If it is falsy, it defaults to `"main"`.
+
+ On error it throws with a description of the problem.
+ */
+ capi.sqlite3_js_db_export = function(pDb, schema=0){
+ pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb);
+ if(!pDb) toss3('Invalid sqlite3* argument.');
+ if(!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.');
+ const scope = wasm.scopedAllocPush();
+ let pOut;
+ try{
+ const pSize = wasm.scopedAlloc(8/*i64*/ + wasm.ptrSizeof);
+ const ppOut = pSize + 8;
+ /**
+ Maintenance reminder, since this cost a full hour of grief
+ and confusion: if the order of pSize/ppOut are reversed in
+ that memory block, fetching the value of pSize after the
+ export reads a garbage size because it's not on an 8-byte
+ memory boundary!
+ */
+ const zSchema = schema
+ ? (wasm.isPtr(schema) ? schema : wasm.scopedAllocCString(''+schema))
+ : 0;
+ let rc = wasm.exports.sqlite3__wasm_db_serialize(
+ pDb, zSchema, ppOut, pSize, 0
+ );
+ if(rc){
+ toss3("Database serialization failed with code",
+ sqlite3.capi.sqlite3_js_rc_str(rc));
+ }
+ pOut = wasm.peekPtr(ppOut);
+ const nOut = wasm.peek(pSize, 'i64');
+ rc = nOut
+ ? wasm.heap8u().slice(pOut, pOut + Number(nOut))
+ : new Uint8Array();
+ return rc;
+ }finally{
+ if(pOut) wasm.exports.sqlite3_free(pOut);
+ wasm.scopedAllocPop(scope);
+ }
+ };
+
+ /**
+ Given a `sqlite3*` and a database name (JS string or WASM
+ C-string pointer, which may be 0), returns a pointer to the
+ sqlite3_vfs responsible for it. If the given db name is null/0,
+ or not provided, then "main" is assumed.
+ */
+ capi.sqlite3_js_db_vfs =
+ (dbPointer, dbName=0)=>util.sqlite3__wasm_db_vfs(dbPointer, dbName);
+
+ /**
+ A thin wrapper around capi.sqlite3_aggregate_context() which
+ behaves the same except that it throws a WasmAllocError if that
+ function returns 0. As a special case, if n is falsy it does
+ _not_ throw if that function returns 0. That special case is
+ intended for use with xFinal() implementations.
+ */
+ capi.sqlite3_js_aggregate_context = (pCtx, n)=>{
+ return capi.sqlite3_aggregate_context(pCtx, n)
+ || (n ? WasmAllocError.toss("Cannot allocate",n,
+ "bytes for sqlite3_aggregate_context()")
+ : 0);
+ };
+
+ /**
+ If the current environment supports the POSIX file APIs, this routine
+ creates (or overwrites) the given file using those APIs. This is
+ primarily intended for use in Emscripten-based builds where the POSIX
+ APIs are transparently proxied by an in-memory virtual filesystem.
+ It may behave diffrently in other environments.
+
+ The first argument must be either a JS string or WASM C-string
+ holding the filename. Note that this routine does _not_ create
+ intermediary directories if the filename has a directory part.
+
+ The 2nd argument may either a valid WASM memory pointer, an
+ ArrayBuffer, or a Uint8Array. The 3rd must be the length, in
+ bytes, of the data array to copy. If the 2nd argument is an
+ ArrayBuffer or Uint8Array and the 3rd is not a positive integer
+ then the 3rd defaults to the array's byteLength value.
+
+ Results are undefined if data is a WASM pointer and dataLen is
+ exceeds data's bounds.
+
+ Throws if any arguments are invalid or if creating or writing to
+ the file fails.
+
+ Added in 3.43 as an alternative for the deprecated
+ sqlite3_js_vfs_create_file().
+ */
+ capi.sqlite3_js_posix_create_file = function(filename, data, dataLen){
+ let pData;
+ if(data && wasm.isPtr(data)){
+ pData = data;
+ }else if(data instanceof ArrayBuffer || data instanceof Uint8Array){
+ pData = wasm.allocFromTypedArray(data);
+ if(arguments.length<3 || !util.isInt32(dataLen) || dataLen<0){
+ dataLen = data.byteLength;
+ }
+ }else{
+ SQLite3Error.toss("Invalid 2nd argument for sqlite3_js_posix_create_file().");
+ }
+ try{
+ if(!util.isInt32(dataLen) || dataLen<0){
+ SQLite3Error.toss("Invalid 3rd argument for sqlite3_js_posix_create_file().");
+ }
+ const rc = util.sqlite3__wasm_posix_create_file(filename, pData, dataLen);
+ if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
+ capi.sqlite3_js_rc_str(rc));
+ }finally{
+ wasm.dealloc(pData);
+ }
+ };
+
+ /**
+ Deprecation warning: this function does not work properly in
+ debug builds of sqlite3 because its out-of-scope use of the
+ sqlite3_vfs API triggers assertions in the core library. That
+ was unfortunately not discovered until 2023-08-11. This function
+ is now deprecated and should not be used in new code.
+
+ Alternative options:
+
+ - "unix" VFS and its variants can get equivalent functionality
+ with sqlite3_js_posix_create_file().
+
+ - OPFS: use either sqlite3.oo1.OpfsDb.importDb(), for the "opfs"
+ VFS, or the importDb() method of the PoolUtil object provided
+ by the "opfs-sahpool" OPFS (noting that its VFS name may differ
+ depending on client-side configuration). We cannot proxy those
+ from here because the former is necessarily asynchronous and
+ the latter requires information not available to this function.
+
+ Creates a file using the storage appropriate for the given
+ sqlite3_vfs. The first argument may be a VFS name (JS string
+ only, NOT a WASM C-string), WASM-managed `sqlite3_vfs*`, or
+ a capi.sqlite3_vfs instance. Pass 0 (a NULL pointer) to use the
+ default VFS. If passed a string which does not resolve using
+ sqlite3_vfs_find(), an exception is thrown. (Note that a WASM
+ C-string is not accepted because it is impossible to
+ distinguish from a C-level `sqlite3_vfs*`.)
+
+ The second argument, the filename, must be a JS or WASM C-string.
+
+ The 3rd may either be falsy, a valid WASM memory pointer, an
+ ArrayBuffer, or a Uint8Array. The 4th must be the length, in
+ bytes, of the data array to copy. If the 3rd argument is an
+ ArrayBuffer or Uint8Array and the 4th is not a positive integer
+ then the 4th defaults to the array's byteLength value.
+
+ If data is falsy then a file is created with dataLen bytes filled
+ with uninitialized data (whatever truncate() leaves there). If
+ data is not falsy then a file is created or truncated and it is
+ filled with the first dataLen bytes of the data source.
+
+ Throws if any arguments are invalid or if creating or writing to
+ the file fails.
+
+ Note that most VFSes do _not_ automatically create directory
+ parts of filenames, nor do all VFSes have a concept of
+ directories. If the given filename is not valid for the given
+ VFS, an exception will be thrown. This function exists primarily
+ to assist in implementing file-upload capability, with the caveat
+ that clients must have some idea of the VFS into which they want
+ to upload and that VFS must support the operation.
+
+ VFS-specific notes:
+
+ - "memdb": results are undefined.
+
+ - "kvvfs": will fail with an I/O error due to strict internal
+ requirments of that VFS's xTruncate().
+
+ - "unix" and related: will use the WASM build's equivalent of the
+ POSIX I/O APIs. This will work so long as neither a specific
+ VFS nor the WASM environment imposes requirements which break it.
+
+ - "opfs": uses OPFS storage and creates directory parts of the
+ filename. It can only be used to import an SQLite3 database
+ file and will fail if given anything else.
+ */
+ capi.sqlite3_js_vfs_create_file = function(vfs, filename, data, dataLen){
+ config.warn("sqlite3_js_vfs_create_file() is deprecated and",
+ "should be avoided because it can lead to C-level crashes.",
+ "See its documentation for alternative options.");
+ let pData;
+ if(data){
+ if(wasm.isPtr(data)){
+ pData = data;
+ }else if(data instanceof ArrayBuffer){
+ data = new Uint8Array(data);
+ }
+ if(data instanceof Uint8Array){
+ pData = wasm.allocFromTypedArray(data);
+ if(arguments.length<4 || !util.isInt32(dataLen) || dataLen<0){
+ dataLen = data.byteLength;
+ }
+ }else{
+ SQLite3Error.toss("Invalid 3rd argument type for sqlite3_js_vfs_create_file().");
+ }
+ }else{
+ pData = 0;
+ }
+ if(!util.isInt32(dataLen) || dataLen<0){
+ wasm.dealloc(pData);
+ SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file().");
+ }
+ try{
+ const rc = util.sqlite3__wasm_vfs_create_file(vfs, filename, pData, dataLen);
+ if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
+ capi.sqlite3_js_rc_str(rc));
+ }finally{
+ wasm.dealloc(pData);
+ }
+ };
+
+ /**
+ Converts SQL input from a variety of convenient formats
+ to plain strings.
+
+ If v is a string, it is returned as-is. If it is-a Array, its
+ join("") result is returned. If is is a Uint8Array, Int8Array,
+ or ArrayBuffer, it is assumed to hold UTF-8-encoded text and is
+ decoded to a string. If it looks like a WASM pointer,
+ wasm.cstrToJs(sql) is returned. Else undefined is returned.
+
+ Added in 3.44
+ */
+ capi.sqlite3_js_sql_to_string = (sql)=>{
+ if('string' === typeof sql){
+ return sql;
+ }
+ const x = flexibleString(v);
+ return x===v ? undefined : x;
+ }
+
+ if( util.isUIThread() ){
+ /* Features specific to the main window thread... */
+
+ /**
+ Internal helper for sqlite3_js_kvvfs_clear() and friends.
+ Its argument should be one of ('local','session',"").
+ */
+ const __kvvfsInfo = function(which){
+ const rc = Object.create(null);
+ rc.prefix = 'kvvfs-'+which;
+ rc.stores = [];
+ if('session'===which || ""===which) rc.stores.push(globalThis.sessionStorage);
+ if('local'===which || ""===which) rc.stores.push(globalThis.localStorage);
+ return rc;
+ };
+
+ /**
+ Clears all storage used by the kvvfs DB backend, deleting any
+ DB(s) stored there. Its argument must be either 'session',
+ 'local', or "". In the first two cases, only sessionStorage
+ resp. localStorage is cleared. If it's an empty string (the
+ default) then both are cleared. Only storage keys which match
+ the pattern used by kvvfs are cleared: any other client-side
+ data are retained.
+
+ This function is only available in the main window thread.
+
+ Returns the number of entries cleared.
+ */
+ capi.sqlite3_js_kvvfs_clear = function(which=""){
+ let rc = 0;
+ const kvinfo = __kvvfsInfo(which);
+ kvinfo.stores.forEach((s)=>{
+ const toRm = [] /* keys to remove */;
+ let i;
+ for( i = 0; i < s.length; ++i ){
+ const k = s.key(i);
+ if(k.startsWith(kvinfo.prefix)) toRm.push(k);
+ }
+ toRm.forEach((kk)=>s.removeItem(kk));
+ rc += toRm.length;
+ });
+ return rc;
+ };
+
+ /**
+ This routine guesses the approximate amount of
+ window.localStorage and/or window.sessionStorage in use by the
+ kvvfs database backend. Its argument must be one of
+ ('session', 'local', ""). In the first two cases, only
+ sessionStorage resp. localStorage is counted. If it's an empty
+ string (the default) then both are counted. Only storage keys
+ which match the pattern used by kvvfs are counted. The returned
+ value is the "length" value of every matching key and value,
+ noting that JavaScript stores each character in 2 bytes.
+
+ Note that the returned size is not authoritative from the
+ perspective of how much data can fit into localStorage and
+ sessionStorage, as the precise algorithms for determining
+ those limits are unspecified and may include per-entry
+ overhead invisible to clients.
+ */
+ capi.sqlite3_js_kvvfs_size = function(which=""){
+ let sz = 0;
+ const kvinfo = __kvvfsInfo(which);
+ kvinfo.stores.forEach((s)=>{
+ let i;
+ for(i = 0; i < s.length; ++i){
+ const k = s.key(i);
+ if(k.startsWith(kvinfo.prefix)){
+ sz += k.length;
+ sz += s.getItem(k).length;
+ }
+ }
+ });
+ return sz * 2 /* because JS uses 2-byte char encoding */;
+ };
+
+ }/* main-window-only bits */
+
+ /**
+ Wraps all known variants of the C-side variadic
+ sqlite3_db_config().
+
+ Full docs: https://sqlite.org/c3ref/db_config.html
+
+ Returns capi.SQLITE_MISUSE if op is not a valid operation ID.
+
+ The variants which take `(int, int*)` arguments treat a
+ missing or falsy pointer argument as 0.
+ */
+ capi.sqlite3_db_config = function(pDb, op, ...args){
+ if(!this.s){
+ this.s = wasm.xWrap('sqlite3__wasm_db_config_s','int',
+ ['sqlite3*', 'int', 'string:static']
+ /* MAINDBNAME requires a static string */);
+ this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int',
+ ['sqlite3*', 'int', '*','int', 'int']);
+ this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int',
+ ['sqlite3*', 'int', 'int','*']);
+ }
+ switch(op){
+ case capi.SQLITE_DBCONFIG_ENABLE_FKEY:
+ case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER:
+ case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
+ case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
+ case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
+ case capi.SQLITE_DBCONFIG_ENABLE_QPSG:
+ case capi.SQLITE_DBCONFIG_TRIGGER_EQP:
+ case capi.SQLITE_DBCONFIG_RESET_DATABASE:
+ case capi.SQLITE_DBCONFIG_DEFENSIVE:
+ case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA:
+ case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
+ case capi.SQLITE_DBCONFIG_DQS_DML:
+ case capi.SQLITE_DBCONFIG_DQS_DDL:
+ case capi.SQLITE_DBCONFIG_ENABLE_VIEW:
+ case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
+ case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA:
+ case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS:
+ case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER:
+ return this.ip(pDb, op, args[0], args[1] || 0);
+ case capi.SQLITE_DBCONFIG_LOOKASIDE:
+ return this.pii(pDb, op, args[0], args[1], args[2]);
+ case capi.SQLITE_DBCONFIG_MAINDBNAME:
+ return this.s(pDb, op, args[0]);
+ default:
+ return capi.SQLITE_MISUSE;
+ }
+ }.bind(Object.create(null));
+
+ /**
+ Given a (sqlite3_value*), this function attempts to convert it
+ to an equivalent JS value with as much fidelity as feasible and
+ return it.
+
+ By default it throws if it cannot determine any sensible
+ conversion. If passed a falsy second argument, it instead returns
+ `undefined` if no suitable conversion is found. Note that there
+ is no conversion from SQL to JS which results in the `undefined`
+ value, so `undefined` has an unambiguous meaning here. It will
+ always throw a WasmAllocError if allocating memory for a
+ conversion fails.
+
+ Caveats:
+
+ - It does not support sqlite3_value_to_pointer() conversions
+ because those require a type name string which this function
+ does not have and cannot sensibly be given at the level of the
+ API where this is used (e.g. automatically converting UDF
+ arguments). Clients using sqlite3_value_to_pointer(), and its
+ related APIs, will need to manage those themselves.
+ */
+ capi.sqlite3_value_to_js = function(pVal,throwIfCannotConvert=true){
+ let arg;
+ const valType = capi.sqlite3_value_type(pVal);
+ switch(valType){
+ case capi.SQLITE_INTEGER:
+ if(wasm.bigIntEnabled){
+ arg = capi.sqlite3_value_int64(pVal);
+ if(util.bigIntFitsDouble(arg)) arg = Number(arg);
+ }
+ else arg = capi.sqlite3_value_double(pVal)/*yes, double, for larger integers*/;
+ break;
+ case capi.SQLITE_FLOAT:
+ arg = capi.sqlite3_value_double(pVal);
+ break;
+ case capi.SQLITE_TEXT:
+ arg = capi.sqlite3_value_text(pVal);
+ break;
+ case capi.SQLITE_BLOB:{
+ const n = capi.sqlite3_value_bytes(pVal);
+ const pBlob = capi.sqlite3_value_blob(pVal);
+ if(n && !pBlob) sqlite3.WasmAllocError.toss(
+ "Cannot allocate memory for blob argument of",n,"byte(s)"
+ );
+ arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null;
+ break;
+ }
+ case capi.SQLITE_NULL:
+ arg = null; break;
+ default:
+ if(throwIfCannotConvert){
+ toss3(capi.SQLITE_MISMATCH,
+ "Unhandled sqlite3_value_type():",valType);
+ }
+ arg = undefined;
+ }
+ return arg;
+ };
+
+ /**
+ Requires a C-style array of `sqlite3_value*` objects and the
+ number of entries in that array. Returns a JS array containing
+ the results of passing each C array entry to
+ sqlite3_value_to_js(). The 3rd argument to this function is
+ passed on as the 2nd argument to that one.
+ */
+ capi.sqlite3_values_to_js = function(argc,pArgv,throwIfCannotConvert=true){
+ let i;
+ const tgt = [];
+ for(i = 0; i < argc; ++i){
+ /**
+ Curiously: despite ostensibly requiring 8-byte
+ alignment, the pArgv array is parcelled into chunks of
+ 4 bytes (1 pointer each). The values those point to
+ have 8-byte alignment but the individual argv entries
+ do not.
+ */
+ tgt.push(capi.sqlite3_value_to_js(
+ wasm.peekPtr(pArgv + (wasm.ptrSizeof * i)),
+ throwIfCannotConvert
+ ));
+ }
+ return tgt;
+ };
+
+ /**
+ Calls either sqlite3_result_error_nomem(), if e is-a
+ WasmAllocError, or sqlite3_result_error(). In the latter case,
+ the second argument is coerced to a string to create the error
+ message.
+
+ The first argument is a (sqlite3_context*). Returns void.
+ Does not throw.
+ */
+ capi.sqlite3_result_error_js = function(pCtx,e){
+ if(e instanceof WasmAllocError){
+ capi.sqlite3_result_error_nomem(pCtx);
+ }else{
+ /* Maintenance reminder: ''+e, rather than e.message,
+ will prefix e.message with e.name, so it includes
+ the exception's type name in the result. */;
+ capi.sqlite3_result_error(pCtx, ''+e, -1);
+ }
+ };
+
+ /**
+ This function passes its 2nd argument to one of the
+ sqlite3_result_xyz() routines, depending on the type of that
+ argument:
+
+ - If (val instanceof Error), this function passes it to
+ sqlite3_result_error_js().
+ - `null`: `sqlite3_result_null()`
+ - `boolean`: `sqlite3_result_int()` with a value of 0 or 1.
+ - `number`: `sqlite3_result_int()`, `sqlite3_result_int64()`, or
+ `sqlite3_result_double()`, depending on the range of the number
+ and whether or not int64 support is enabled.
+ - `bigint`: similar to `number` but will trigger an error if the
+ value is too big to store in an int64.
+ - `string`: `sqlite3_result_text()`
+ - Uint8Array or Int8Array or ArrayBuffer: `sqlite3_result_blob()`
+ - `undefined`: is a no-op provided to simplify certain use cases.
+
+ Anything else triggers `sqlite3_result_error()` with a
+ description of the problem.
+
+ The first argument to this function is a `(sqlite3_context*)`.
+ Returns void. Does not throw.
+ */
+ capi.sqlite3_result_js = function(pCtx,val){
+ if(val instanceof Error){
+ capi.sqlite3_result_error_js(pCtx, val);
+ return;
+ }
+ try{
+ switch(typeof val) {
+ case 'undefined':
+ /* This is a no-op. This routine originated in the create_function()
+ family of APIs and in that context, passing in undefined indicated
+ that the caller was responsible for calling sqlite3_result_xxx()
+ (if needed). */
+ break;
+ case 'boolean':
+ capi.sqlite3_result_int(pCtx, val ? 1 : 0);
+ break;
+ case 'bigint':
+ if(util.bigIntFits32(val)){
+ capi.sqlite3_result_int(pCtx, Number(val));
+ }else if(util.bigIntFitsDouble(val)){
+ capi.sqlite3_result_double(pCtx, Number(val));
+ }else if(wasm.bigIntEnabled){
+ if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val);
+ else toss3("BigInt value",val.toString(),"is too BigInt for int64.");
+ }else{
+ toss3("BigInt value",val.toString(),"is too BigInt.");
+ }
+ break;
+ case 'number': {
+ let f;
+ if(util.isInt32(val)){
+ f = capi.sqlite3_result_int;
+ }else if(wasm.bigIntEnabled
+ && Number.isInteger(val)
+ && util.bigIntFits64(BigInt(val))){
+ f = capi.sqlite3_result_int64;
+ }else{
+ f = capi.sqlite3_result_double;
+ }
+ f(pCtx, val);
+ break;
+ }
+ case 'string': {
+ const [p, n] = wasm.allocCString(val,true);
+ capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC);
+ break;
+ }
+ case 'object':
+ if(null===val/*yes, typeof null === 'object'*/) {
+ capi.sqlite3_result_null(pCtx);
+ break;
+ }else if(util.isBindableTypedArray(val)){
+ const pBlob = wasm.allocFromTypedArray(val);
+ capi.sqlite3_result_blob(
+ pCtx, pBlob, val.byteLength,
+ capi.SQLITE_WASM_DEALLOC
+ );
+ break;
+ }
+ // else fall through
+ default:
+ toss3("Don't not how to handle this UDF result value:",(typeof val), val);
+ }
+ }catch(e){
+ capi.sqlite3_result_error_js(pCtx, e);
+ }
+ };
+
+ /**
+ Returns the result sqlite3_column_value(pStmt,iCol) passed to
+ sqlite3_value_to_js(). The 3rd argument of this function is
+ ignored by this function except to pass it on as the second
+ argument of sqlite3_value_to_js(). If the sqlite3_column_value()
+ returns NULL (e.g. because the column index is out of range),
+ this function returns `undefined`, regardless of the 3rd
+ argument. If the 3rd argument is falsy and conversion fails,
+ `undefined` will be returned.
+
+ Note that sqlite3_column_value() returns an "unprotected" value
+ object, but in a single-threaded environment (like this one)
+ there is no distinction between protected and unprotected values.
+ */
+ capi.sqlite3_column_js = function(pStmt, iCol, throwIfCannotConvert=true){
+ const v = capi.sqlite3_column_value(pStmt, iCol);
+ return (0===v) ? undefined : capi.sqlite3_value_to_js(v, throwIfCannotConvert);
+ };
+
+ /**
+ Internal impl of sqlite3_preupdate_new/old_js() and
+ sqlite3changeset_new/old_js().
+ */
+ const __newOldValue = function(pObj, iCol, impl){
+ impl = capi[impl];
+ if(!this.ptr) this.ptr = wasm.allocPtr();
+ else wasm.pokePtr(this.ptr, 0);
+ const rc = impl(pObj, iCol, this.ptr);
+ if(rc) return SQLite3Error.toss(rc,arguments[2]+"() failed with code "+rc);
+ const pv = wasm.peekPtr(this.ptr);
+ return pv ? capi.sqlite3_value_to_js( pv, true ) : undefined;
+ }.bind(Object.create(null));
+
+ /**
+ A wrapper around sqlite3_preupdate_new() which fetches the
+ sqlite3_value at the given index and returns the result of
+ passing it to sqlite3_value_to_js(). Throws on error.
+ */
+ capi.sqlite3_preupdate_new_js =
+ (pDb, iCol)=>__newOldValue(pDb, iCol, 'sqlite3_preupdate_new');
+
+ /**
+ The sqlite3_preupdate_old() counterpart of
+ sqlite3_preupdate_new_js(), with an identical interface.
+ */
+ capi.sqlite3_preupdate_old_js =
+ (pDb, iCol)=>__newOldValue(pDb, iCol, 'sqlite3_preupdate_old');
+
+ /**
+ A wrapper around sqlite3changeset_new() which fetches the
+ sqlite3_value at the given index and returns the result of
+ passing it to sqlite3_value_to_js(). Throws on error.
+
+ If sqlite3changeset_new() succeeds but has no value to report,
+ this function returns the undefined value, noting that undefined
+ is a valid conversion from an `sqlite3_value`, so is unambiguous.
+ */
+ capi.sqlite3changeset_new_js =
+ (pChangesetIter, iCol) => __newOldValue(pChangesetIter, iCol,
+ 'sqlite3changeset_new');
+
+ /**
+ The sqlite3changeset_old() counterpart of
+ sqlite3changeset_new_js(), with an identical interface.
+ */
+ capi.sqlite3changeset_old_js =
+ (pChangesetIter, iCol)=>__newOldValue(pChangesetIter, iCol,
+ 'sqlite3changeset_old');
+
+ /* The remainder of the API will be set up in later steps. */
+ const sqlite3 = {
+ WasmAllocError: WasmAllocError,
+ SQLite3Error: SQLite3Error,
+ capi,
+ util,
+ wasm,
+ config,
+ /**
+ Holds the version info of the sqlite3 source tree from which
+ the generated sqlite3-api.js gets built. Note that its version
+ may well differ from that reported by sqlite3_libversion(), but
+ that should be considered a source file mismatch, as the JS and
+ WASM files are intended to be built and distributed together.
+
+ This object is initially a placeholder which gets replaced by a
+ build-generated object.
+ */
+ version: Object.create(null),
+
+ /**
+ The library reserves the 'client' property for client-side use
+ and promises to never define a property with this name nor to
+ ever rely on specific contents of it. It makes no such guarantees
+ for other properties.
+ */
+ client: undefined,
+
+ /**
+ This function is not part of the public interface, but a
+ piece of internal bootstrapping infrastructure.
+
+ Performs any optional asynchronous library-level initialization
+ which might be required. This function returns a Promise which
+ resolves to the sqlite3 namespace object. Any error in the
+ async init will be fatal to the init as a whole, but init
+ routines are themselves welcome to install dummy catch()
+ handlers which are not fatal if their failure should be
+ considered non-fatal. If called more than once, the second and
+ subsequent calls are no-ops which return a pre-resolved
+ Promise.
+
+ Ideally this function is called as part of the Promise chain
+ which handles the loading and bootstrapping of the API. If not
+ then it must be called by client-level code, which must not use
+ the library until the returned promise resolves.
+
+ If called multiple times it will return the same promise on
+ subsequent calls. The current build setup precludes that
+ possibility, so it's only a hypothetical problem if/when this
+ function ever needs to be invoked by clients.
+
+ In Emscripten-based builds, this function is called
+ automatically and deleted from this object.
+ */
+ asyncPostInit: async function ff(){
+ if(ff.isReady instanceof Promise) return ff.isReady;
+ let lia = sqlite3ApiBootstrap.initializersAsync;
+ delete sqlite3ApiBootstrap.initializersAsync;
+ const postInit = async ()=>{
+ if(!sqlite3.__isUnderTest){
+ /* Delete references to internal-only APIs which are used by
+ some initializers. Retain them when running in test mode
+ so that we can add tests for them. */
+ delete sqlite3.util;
+ /* It's conceivable that we might want to expose
+ StructBinder to client-side code, but it's only useful if
+ clients build their own sqlite3.wasm which contains their
+ own C struct types. */
+ delete sqlite3.StructBinder;
+ }
+ return sqlite3;
+ };
+ const catcher = (e)=>{
+ config.error("an async sqlite3 initializer failed:",e);
+ throw e;
+ };
+ if(!lia || !lia.length){
+ return ff.isReady = postInit().catch(catcher);
+ }
+ lia = lia.map((f)=>{
+ return (f instanceof Function) ? async x=>f(sqlite3) : f;
+ });
+ lia.push(postInit);
+ let p = Promise.resolve(sqlite3);
+ while(lia.length) p = p.then(lia.shift());
+ return ff.isReady = p.catch(catcher);
+ },
+ /**
+ scriptInfo ideally gets injected into this object by the
+ infrastructure which assembles the JS/WASM module. It contains
+ state which must be collected before sqlite3ApiBootstrap() can
+ be declared. It is not necessarily available to any
+ sqlite3ApiBootstrap.initializers but "should" be in place (if
+ it's added at all) by the time that
+ sqlite3ApiBootstrap.initializersAsync is processed.
+
+ This state is not part of the public API, only intended for use
+ with the sqlite3 API bootstrapping and wasm-loading process.
+ */
+ scriptInfo: undefined
+ };
+ try{
+ sqlite3ApiBootstrap.initializers.forEach((f)=>{
+ f(sqlite3);
+ });
+ }catch(e){
+ /* If we don't report this here, it can get completely swallowed
+ up and disappear into the abyss of Promises and Workers. */
+ console.error("sqlite3 bootstrap initializer threw:",e);
+ throw e;
+ }
+ delete sqlite3ApiBootstrap.initializers;
+ sqlite3ApiBootstrap.sqlite3 = sqlite3;
+ return sqlite3;
+}/*sqlite3ApiBootstrap()*/;
+/**
+ globalThis.sqlite3ApiBootstrap.initializers is an internal detail used by
+ the various pieces of the sqlite3 API's amalgamation process. It
+ must not be modified by client code except when plugging such code
+ into the amalgamation process.
+
+ Each component of the amalgamation is expected to append a function
+ to this array. When sqlite3ApiBootstrap() is called for the first
+ time, each such function will be called (in their appended order)
+ and passed the sqlite3 namespace object, into which they can install
+ their features (noting that most will also require that certain
+ features alread have been installed). At the end of that process,
+ this array is deleted.
+
+ Note that the order of insertion into this array is significant for
+ some pieces. e.g. sqlite3.capi and sqlite3.wasm cannot be fully
+ utilized until the whwasmutil.js part is plugged in via
+ sqlite3-api-glue.js.
+*/
+globalThis.sqlite3ApiBootstrap.initializers = [];
+/**
+ globalThis.sqlite3ApiBootstrap.initializersAsync is an internal detail
+ used by the sqlite3 API's amalgamation process. It must not be
+ modified by client code except when plugging such code into the
+ amalgamation process.
+
+ The counterpart of globalThis.sqlite3ApiBootstrap.initializers,
+ specifically for initializers which are asynchronous. All entries in
+ this list must be either async functions, non-async functions which
+ return a Promise, or a Promise. Each function in the list is called
+ with the sqlite3 object as its only argument.
+
+ The resolved value of any Promise is ignored and rejection will kill
+ the asyncPostInit() process (at an indeterminate point because all
+ of them are run asynchronously in parallel).
+
+ This list is not processed until the client calls
+ sqlite3.asyncPostInit(). This means, for example, that intializers
+ added to globalThis.sqlite3ApiBootstrap.initializers may push entries to
+ this list.
+*/
+globalThis.sqlite3ApiBootstrap.initializersAsync = [];
+/**
+ Client code may assign sqlite3ApiBootstrap.defaultConfig an
+ object-type value before calling sqlite3ApiBootstrap() (without
+ arguments) in order to tell that call to use this object as its
+ default config value. The intention of this is to provide
+ downstream clients with a reasonably flexible approach for plugging in
+ an environment-suitable configuration without having to define a new
+ global-scope symbol.
+*/
+globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null);
+/**
+ Placeholder: gets installed by the first call to
+ globalThis.sqlite3ApiBootstrap(). However, it is recommended that the
+ caller of sqlite3ApiBootstrap() capture its return value and delete
+ globalThis.sqlite3ApiBootstrap after calling it. It returns the same
+ value which will be stored here.
+*/
+globalThis.sqlite3ApiBootstrap.sqlite3 = undefined;
+/* END FILE: api/sqlite3-api-prologue.js */
+/* BEGIN FILE: common/whwasmutil.js */
+/**
+ 2022-07-08
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ The whwasmutil is developed in conjunction with the Jaccwabyt
+ project:
+
+ https://fossil.wanderinghorse.net/r/jaccwabyt
+
+ and sqlite3:
+
+ https://sqlite.org
+
+ This file is kept in sync between both of those trees.
+
+ Maintenance reminder: If you're reading this in a tree other than
+ one of those listed above, note that this copy may be replaced with
+ upstream copies of that one from time to time. Thus the code
+ installed by this function "should not" be edited outside of those
+ projects, else it risks getting overwritten.
+*/
+/**
+ This function is intended to simplify porting around various bits
+ of WASM-related utility code from project to project.
+
+ The primary goal of this code is to replace, where possible,
+ Emscripten-generated glue code with equivalent utility code which
+ can be used in arbitrary WASM environments built with toolchains
+ other than Emscripten. As of this writing, this code is capable of
+ acting as a replacement for Emscripten's generated glue code
+ _except_ that the latter installs handlers for Emscripten-provided
+ APIs such as its "FS" (virtual filesystem) API. Loading of such
+ things still requires using Emscripten's glue, but the post-load
+ utility APIs provided by this code are still usable as replacements
+ for their sub-optimally-documented Emscripten counterparts.
+
+ Intended usage:
+
+ ```
+ globalThis.WhWasmUtilInstaller(appObject);
+ delete globalThis.WhWasmUtilInstaller;
+ ```
+
+ Its global-scope symbol is intended only to provide an easy way to
+ make it available to 3rd-party scripts and "should" be deleted
+ after calling it. That symbols is _not_ used within the library.
+
+ Forewarning: this API explicitly targets only browser
+ environments. If a given non-browser environment has the
+ capabilities needed for a given feature (e.g. TextEncoder), great,
+ but it does not go out of its way to account for them and does not
+ provide compatibility crutches for them.
+
+ It currently offers alternatives to the following
+ Emscripten-generated APIs:
+
+ - OPTIONALLY memory allocation, but how this gets imported is
+ environment-specific. Most of the following features only work
+ if allocation is available.
+
+ - WASM-exported "indirect function table" access and
+ manipulation. e.g. creating new WASM-side functions using JS
+ functions, analog to Emscripten's addFunction() and
+ uninstallFunction() but slightly different.
+
+ - Get/set specific heap memory values, analog to Emscripten's
+ getValue() and setValue().
+
+ - String length counting in UTF-8 bytes (C-style and JS strings).
+
+ - JS string to C-string conversion and vice versa, analog to
+ Emscripten's stringToUTF8Array() and friends, but with slighter
+ different interfaces.
+
+ - JS string to Uint8Array conversion, noting that browsers actually
+ already have this built in via TextEncoder.
+
+ - "Scoped" allocation, such that allocations made inside of a given
+ explicit scope will be automatically cleaned up when the scope is
+ closed. This is fundamentally similar to Emscripten's
+ stackAlloc() and friends but uses the heap instead of the stack
+ because access to the stack requires C code.
+
+ - Create JS wrappers for WASM functions, analog to Emscripten's
+ ccall() and cwrap() functions, except that the automatic
+ conversions for function arguments and return values can be
+ easily customized by the client by assigning custom function
+ signature type names to conversion functions. Essentially,
+ it's ccall() and cwrap() on steroids.
+
+ How to install...
+
+ Passing an object to this function will install the functionality
+ into that object. Afterwards, client code "should" delete the global
+ symbol.
+
+ This code requires that the target object have the following
+ properties, noting that they needn't be available until the first
+ time one of the installed APIs is used (as opposed to when this
+ function is called) except where explicitly noted:
+
+ - `exports` must be a property of the target object OR a property
+ of `target.instance` (a WebAssembly.Module instance) and it must
+ contain the symbols exported by the WASM module associated with
+ this code. In an Enscripten environment it must be set to
+ `Module['asm']` (versions <=3.1.43) or `wasmExports` (versions
+ >=3.1.44). The exports object must contain a minimum of the
+ following symbols:
+
+ - `memory`: a WebAssembly.Memory object representing the WASM
+ memory. _Alternately_, the `memory` property can be set as
+ `target.memory`, in particular if the WASM heap memory is
+ initialized in JS an _imported_ into WASM, as opposed to being
+ initialized in WASM and exported to JS.
+
+ - `__indirect_function_table`: the WebAssembly.Table object which
+ holds WASM-exported functions. This API does not strictly
+ require that the table be able to grow but it will throw if its
+ `installFunction()` is called and the table cannot grow.
+
+ In order to simplify downstream usage, if `target.exports` is not
+ set when this is called then a property access interceptor
+ (read-only, configurable, enumerable) gets installed as `exports`
+ which resolves to `target.instance.exports`, noting that the latter
+ property need not exist until the first time `target.exports` is
+ accessed.
+
+ Some APIs _optionally_ make use of the `bigIntEnabled` property of
+ the target object. It "should" be set to true if the WASM
+ environment is compiled with BigInt support, else it must be
+ false. If it is false, certain BigInt-related features will trigger
+ an exception if invoked. This property, if not set when this is
+ called, will get a default value of true only if the BigInt64Array
+ constructor is available, else it will default to false. Note that
+ having the BigInt type is not sufficient for full int64 integration
+ with WASM: the target WASM file must also have been built with
+ that support. In Emscripten that's done using the `-sWASM_BIGINT`
+ flag.
+
+ Some optional APIs require that the target have the following
+ methods:
+
+ - 'alloc()` must behave like C's `malloc()`, allocating N bytes of
+ memory and returning its pointer. In Emscripten this is
+ conventionally made available via `Module['_malloc']`. This API
+ requires that the alloc routine throw on allocation error, as
+ opposed to returning null or 0.
+
+ - 'dealloc()` must behave like C's `free()`, accepting either a
+ pointer returned from its allocation counterpart or the values
+ null/0 (for which it must be a no-op). In Emscripten this is
+ conventionally made available via `Module['_free']`.
+
+ APIs which require allocation routines are explicitly documented as
+ such and/or have "alloc" in their names.
+
+ This code is developed and maintained in conjunction with the
+ Jaccwabyt project:
+
+ https://fossil.wanderinghorse.net/r/jaccwabbyt
+
+ More specifically:
+
+ https://fossil.wanderinghorse.net/r/jaccwabbyt/file/common/whwasmutil.js
+*/
+globalThis.WhWasmUtilInstaller = function(target){
+ 'use strict';
+ if(undefined===target.bigIntEnabled){
+ target.bigIntEnabled = !!globalThis['BigInt64Array'];
+ }
+
+ /** Throws a new Error, the message of which is the concatenation of
+ all args with a space between each. */
+ const toss = (...args)=>{throw new Error(args.join(' '))};
+
+ if(!target.exports){
+ Object.defineProperty(target, 'exports', {
+ enumerable: true, configurable: true,
+ get: ()=>(target.instance && target.instance.exports)
+ });
+ }
+
+ /*********
+ alloc()/dealloc() auto-install...
+
+ This would be convenient but it can also cause us to pick up
+ malloc() even when the client code is using a different exported
+ allocator (who, me?), which is bad. malloc() may be exported even
+ if we're not explicitly using it and overriding the malloc()
+ function, linking ours first, is not always feasible when using a
+ malloc() proxy, as it can lead to recursion and stack overflow
+ (who, me?). So... we really need the downstream code to set up
+ target.alloc/dealloc() itself.
+ ******/
+ /******
+ if(target.exports){
+ //Maybe auto-install alloc()/dealloc()...
+ if(!target.alloc && target.exports.malloc){
+ target.alloc = function(n){
+ const m = this(n);
+ return m || toss("Allocation of",n,"byte(s) failed.");
+ }.bind(target.exports.malloc);
+ }
+
+ if(!target.dealloc && target.exports.free){
+ target.dealloc = function(ptr){
+ if(ptr) this(ptr);
+ }.bind(target.exports.free);
+ }
+ }*******/
+
+ /**
+ Pointers in WASM are currently assumed to be 32-bit, but someday
+ that will certainly change.
+ */
+ const ptrIR = target.pointerIR || 'i32';
+ const ptrSizeof = target.ptrSizeof =
+ ('i32'===ptrIR ? 4
+ : ('i64'===ptrIR
+ ? 8 : toss("Unhandled ptrSizeof:",ptrIR)));
+ /** Stores various cached state. */
+ const cache = Object.create(null);
+ /** Previously-recorded size of cache.memory.buffer, noted so that
+ we can recreate the view objects if the heap grows. */
+ cache.heapSize = 0;
+ /** WebAssembly.Memory object extracted from target.memory or
+ target.exports.memory the first time heapWrappers() is
+ called. */
+ cache.memory = null;
+ /** uninstallFunction() puts table indexes in here for reuse and
+ installFunction() extracts them. */
+ cache.freeFuncIndexes = [];
+ /**
+ Used by scopedAlloc() and friends.
+ */
+ cache.scopedAlloc = [];
+
+ cache.utf8Decoder = new TextDecoder();
+ cache.utf8Encoder = new TextEncoder('utf-8');
+
+ /**
+ For the given IR-like string in the set ('i8', 'i16', 'i32',
+ 'f32', 'float', 'i64', 'f64', 'double', '*'), or any string value
+ ending in '*', returns the sizeof for that value
+ (target.ptrSizeof in the latter case). For any other value, it
+ returns the undefined value.
+ */
+ target.sizeofIR = (n)=>{
+ switch(n){
+ case 'i8': return 1;
+ case 'i16': return 2;
+ case 'i32': case 'f32': case 'float': return 4;
+ case 'i64': case 'f64': case 'double': return 8;
+ case '*': return ptrSizeof;
+ default:
+ return (''+n).endsWith('*') ? ptrSizeof : undefined;
+ }
+ };
+
+ /**
+ If (cache.heapSize !== cache.memory.buffer.byteLength), i.e. if
+ the heap has grown since the last call, updates cache.HEAPxyz.
+ Returns the cache object.
+ */
+ const heapWrappers = function(){
+ if(!cache.memory){
+ cache.memory = (target.memory instanceof WebAssembly.Memory)
+ ? target.memory : target.exports.memory;
+ }else if(cache.heapSize === cache.memory.buffer.byteLength){
+ return cache;
+ }
+ // heap is newly-acquired or has been resized....
+ const b = cache.memory.buffer;
+ cache.HEAP8 = new Int8Array(b); cache.HEAP8U = new Uint8Array(b);
+ cache.HEAP16 = new Int16Array(b); cache.HEAP16U = new Uint16Array(b);
+ cache.HEAP32 = new Int32Array(b); cache.HEAP32U = new Uint32Array(b);
+ if(target.bigIntEnabled){
+ cache.HEAP64 = new BigInt64Array(b); cache.HEAP64U = new BigUint64Array(b);
+ }
+ cache.HEAP32F = new Float32Array(b); cache.HEAP64F = new Float64Array(b);
+ cache.heapSize = b.byteLength;
+ return cache;
+ };
+
+ /** Convenience equivalent of this.heapForSize(8,false). */
+ target.heap8 = ()=>heapWrappers().HEAP8;
+
+ /** Convenience equivalent of this.heapForSize(8,true). */
+ target.heap8u = ()=>heapWrappers().HEAP8U;
+
+ /** Convenience equivalent of this.heapForSize(16,false). */
+ target.heap16 = ()=>heapWrappers().HEAP16;
+
+ /** Convenience equivalent of this.heapForSize(16,true). */
+ target.heap16u = ()=>heapWrappers().HEAP16U;
+
+ /** Convenience equivalent of this.heapForSize(32,false). */
+ target.heap32 = ()=>heapWrappers().HEAP32;
+
+ /** Convenience equivalent of this.heapForSize(32,true). */
+ target.heap32u = ()=>heapWrappers().HEAP32U;
+
+ /**
+ Requires n to be one of:
+
+ - integer 8, 16, or 32.
+ - A integer-type TypedArray constructor: Int8Array, Int16Array,
+ Int32Array, or their Uint counterparts.
+
+ If this.bigIntEnabled is true, it also accepts the value 64 or a
+ BigInt64Array/BigUint64Array, else it throws if passed 64 or one
+ of those constructors.
+
+ Returns an integer-based TypedArray view of the WASM heap
+ memory buffer associated with the given block size. If passed
+ an integer as the first argument and unsigned is truthy then
+ the "U" (unsigned) variant of that view is returned, else the
+ signed variant is returned. If passed a TypedArray value, the
+ 2nd argument is ignored. Note that Float32Array and
+ Float64Array views are not supported by this function.
+
+ Note that growth of the heap will invalidate any references to
+ this heap, so do not hold a reference longer than needed and do
+ not use a reference after any operation which may
+ allocate. Instead, re-fetch the reference by calling this
+ function again.
+
+ Throws if passed an invalid n.
+
+ Pedantic side note: the name "heap" is a bit of a misnomer. In a
+ WASM environment, the stack and heap memory are all accessed via
+ the same view(s) of the memory.
+ */
+ target.heapForSize = function(n,unsigned = true){
+ let ctor;
+ const c = (cache.memory && cache.heapSize === cache.memory.buffer.byteLength)
+ ? cache : heapWrappers();
+ switch(n){
+ case Int8Array: return c.HEAP8; case Uint8Array: return c.HEAP8U;
+ case Int16Array: return c.HEAP16; case Uint16Array: return c.HEAP16U;
+ case Int32Array: return c.HEAP32; case Uint32Array: return c.HEAP32U;
+ case 8: return unsigned ? c.HEAP8U : c.HEAP8;
+ case 16: return unsigned ? c.HEAP16U : c.HEAP16;
+ case 32: return unsigned ? c.HEAP32U : c.HEAP32;
+ case 64:
+ if(c.HEAP64) return unsigned ? c.HEAP64U : c.HEAP64;
+ break;
+ default:
+ if(target.bigIntEnabled){
+ if(n===globalThis['BigUint64Array']) return c.HEAP64U;
+ else if(n===globalThis['BigInt64Array']) return c.HEAP64;
+ break;
+ }
+ }
+ toss("Invalid heapForSize() size: expecting 8, 16, 32,",
+ "or (if BigInt is enabled) 64.");
+ };
+
+ /**
+ Returns the WASM-exported "indirect function table."
+ */
+ target.functionTable = function(){
+ return target.exports.__indirect_function_table;
+ /** -----------------^^^^^ "seems" to be a standardized export name.
+ From Emscripten release notes from 2020-09-10:
+ - Use `__indirect_function_table` as the import name for the
+ table, which is what LLVM does.
+ */
+ };
+
+ /**
+ Given a function pointer, returns the WASM function table entry
+ if found, else returns a falsy value: undefined if fptr is out of
+ range or null if it's in range but the table entry is empty.
+ */
+ target.functionEntry = function(fptr){
+ const ft = target.functionTable();
+ return fptr < ft.length ? ft.get(fptr) : undefined;
+ };
+
+ /**
+ Creates a WASM function which wraps the given JS function and
+ returns the JS binding of that WASM function. The signature
+ string must be the Jaccwabyt-format or Emscripten
+ addFunction()-format function signature string. In short: in may
+ have one of the following formats:
+
+ - Emscripten: `"x..."`, where the first x is a letter representing
+ the result type and subsequent letters represent the argument
+ types. Functions with no arguments have only a single
+ letter. See below.
+
+ - Jaccwabyt: `"x(...)"` where `x` is the letter representing the
+ result type and letters in the parens (if any) represent the
+ argument types. Functions with no arguments use `x()`. See
+ below.
+
+ Supported letters:
+
+ - `i` = int32
+ - `p` = int32 ("pointer")
+ - `j` = int64
+ - `f` = float32
+ - `d` = float64
+ - `v` = void, only legal for use as the result type
+
+ It throws if an invalid signature letter is used.
+
+ Jaccwabyt-format signatures support some additional letters which
+ have no special meaning here but (in this context) act as aliases
+ for other letters:
+
+ - `s`, `P`: same as `p`
+
+ Sidebar: this code is developed together with Jaccwabyt, thus the
+ support for its signature format.
+
+ The arguments may be supplied in either order: (func,sig) or
+ (sig,func).
+ */
+ target.jsFuncToWasm = function f(func, sig){
+ /** Attribution: adapted up from Emscripten-generated glue code,
+ refactored primarily for efficiency's sake, eliminating
+ call-local functions and superfluous temporary arrays. */
+ if(!f._){/*static init...*/
+ f._ = {
+ // Map of signature letters to type IR values
+ sigTypes: Object.assign(Object.create(null),{
+ i: 'i32', p: 'i32', P: 'i32', s: 'i32',
+ j: 'i64', f: 'f32', d: 'f64'
+ }),
+ // Map of type IR values to WASM type code values
+ typeCodes: Object.assign(Object.create(null),{
+ f64: 0x7c, f32: 0x7d, i64: 0x7e, i32: 0x7f
+ }),
+ /** Encodes n, which must be <2^14 (16384), into target array
+ tgt, as a little-endian value, using the given method
+ ('push' or 'unshift'). */
+ uleb128Encode: function(tgt, method, n){
+ if(n<128) tgt[method](n);
+ else tgt[method]( (n % 128) | 128, n>>7);
+ },
+ /** Intentionally-lax pattern for Jaccwabyt-format function
+ pointer signatures, the intent of which is simply to
+ distinguish them from Emscripten-format signatures. The
+ downstream checks are less lax. */
+ rxJSig: /^(\w)\((\w*)\)$/,
+ /** Returns the parameter-value part of the given signature
+ string. */
+ sigParams: function(sig){
+ const m = f._.rxJSig.exec(sig);
+ return m ? m[2] : sig.substr(1);
+ },
+ /** Returns the IR value for the given letter or throws
+ if the letter is invalid. */
+ letterType: (x)=>f._.sigTypes[x] || toss("Invalid signature letter:",x),
+ /** Returns an object describing the result type and parameter
+ type(s) of the given function signature, or throws if the
+ signature is invalid. */
+ /******** // only valid for use with the WebAssembly.Function ctor, which
+ // is not yet documented on MDN.
+ sigToWasm: function(sig){
+ const rc = {parameters:[], results: []};
+ if('v'!==sig[0]) rc.results.push(f.sigTypes(sig[0]));
+ for(const x of f._.sigParams(sig)){
+ rc.parameters.push(f._.typeCodes(x));
+ }
+ return rc;
+ },************/
+ /** Pushes the WASM data type code for the given signature
+ letter to the given target array. Throws if letter is
+ invalid. */
+ pushSigType: (dest, letter)=>dest.push(f._.typeCodes[f._.letterType(letter)])
+ };
+ }/*static init*/
+ if('string'===typeof func){
+ const x = sig;
+ sig = func;
+ func = x;
+ }
+ const sigParams = f._.sigParams(sig);
+ const wasmCode = [0x01/*count: 1*/, 0x60/*function*/];
+ f._.uleb128Encode(wasmCode, 'push', sigParams.length);
+ for(const x of sigParams) f._.pushSigType(wasmCode, x);
+ if('v'===sig[0]) wasmCode.push(0);
+ else{
+ wasmCode.push(1);
+ f._.pushSigType(wasmCode, sig[0]);
+ }
+ f._.uleb128Encode(wasmCode, 'unshift', wasmCode.length)/* type section length */;
+ wasmCode.unshift(
+ 0x00, 0x61, 0x73, 0x6d, /* magic: "\0asm" */
+ 0x01, 0x00, 0x00, 0x00, /* version: 1 */
+ 0x01 /* type section code */
+ );
+ wasmCode.push(
+ /* import section: */ 0x02, 0x07,
+ /* (import "e" "f" (func 0 (type 0))): */
+ 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00,
+ /* export section: */ 0x07, 0x05,
+ /* (export "f" (func 0 (type 0))): */
+ 0x01, 0x01, 0x66, 0x00, 0x00
+ );
+ return (new WebAssembly.Instance(
+ new WebAssembly.Module(new Uint8Array(wasmCode)), {
+ e: { f: func }
+ })).exports['f'];
+ }/*jsFuncToWasm()*/;
+
+ /**
+ Documented as target.installFunction() except for the 3rd
+ argument: if truthy, the newly-created function pointer
+ is stashed in the current scoped-alloc scope and will be
+ cleaned up at the matching scopedAllocPop(), else it
+ is not stashed there.
+ */
+ const __installFunction = function f(func, sig, scoped){
+ if(scoped && !cache.scopedAlloc.length){
+ toss("No scopedAllocPush() scope is active.");
+ }
+ if('string'===typeof func){
+ const x = sig;
+ sig = func;
+ func = x;
+ }
+ if('string'!==typeof sig || !(func instanceof Function)){
+ toss("Invalid arguments: expecting (function,signature) "+
+ "or (signature,function).");
+ }
+ const ft = target.functionTable();
+ const oldLen = ft.length;
+ let ptr;
+ while(cache.freeFuncIndexes.length){
+ ptr = cache.freeFuncIndexes.pop();
+ if(ft.get(ptr)){ /* Table was modified via a different API */
+ ptr = null;
+ continue;
+ }else{
+ break;
+ }
+ }
+ if(!ptr){
+ ptr = oldLen;
+ ft.grow(1);
+ }
+ try{
+ /*this will only work if func is a WASM-exported function*/
+ ft.set(ptr, func);
+ if(scoped){
+ cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr);
+ }
+ return ptr;
+ }catch(e){
+ if(!(e instanceof TypeError)){
+ if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen);
+ throw e;
+ }
+ }
+ // It's not a WASM-exported function, so compile one...
+ try {
+ const fptr = target.jsFuncToWasm(func, sig);
+ ft.set(ptr, fptr);
+ if(scoped){
+ cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr);
+ }
+ }catch(e){
+ if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen);
+ throw e;
+ }
+ return ptr;
+ };
+
+ /**
+ Expects a JS function and signature, exactly as for
+ this.jsFuncToWasm(). It uses that function to create a
+ WASM-exported function, installs that function to the next
+ available slot of this.functionTable(), and returns the
+ function's index in that table (which acts as a pointer to that
+ function). The returned pointer can be passed to
+ uninstallFunction() to uninstall it and free up the table slot for
+ reuse.
+
+ If passed (string,function) arguments then it treats the first
+ argument as the signature and second as the function.
+
+ As a special case, if the passed-in function is a WASM-exported
+ function then the signature argument is ignored and func is
+ installed as-is, without requiring re-compilation/re-wrapping.
+
+ This function will propagate an exception if
+ WebAssembly.Table.grow() throws or this.jsFuncToWasm() throws.
+ The former case can happen in an Emscripten-compiled
+ environment when building without Emscripten's
+ `-sALLOW_TABLE_GROWTH` flag.
+
+ Sidebar: this function differs from Emscripten's addFunction()
+ _primarily_ in that it does not share that function's
+ undocumented behavior of reusing a function if it's passed to
+ addFunction() more than once, which leads to uninstallFunction()
+ breaking clients which do not take care to avoid that case:
+
+ https://github.com/emscripten-core/emscripten/issues/17323
+ */
+ target.installFunction = (func, sig)=>__installFunction(func, sig, false);
+
+ /**
+ Works exactly like installFunction() but requires that a
+ scopedAllocPush() is active and uninstalls the given function
+ when that alloc scope is popped via scopedAllocPop().
+ This is used for implementing JS/WASM function bindings which
+ should only persist for the life of a call into a single
+ C-side function.
+ */
+ target.scopedInstallFunction = (func, sig)=>__installFunction(func, sig, true);
+
+ /**
+ Requires a pointer value previously returned from
+ this.installFunction(). Removes that function from the WASM
+ function table, marks its table slot as free for re-use, and
+ returns that function. It is illegal to call this before
+ installFunction() has been called and results are undefined if
+ ptr was not returned by that function. The returned function
+ may be passed back to installFunction() to reinstall it.
+
+ To simplify certain use cases, if passed a falsy non-0 value
+ (noting that 0 is a valid function table index), this function
+ has no side effects and returns undefined.
+ */
+ target.uninstallFunction = function(ptr){
+ if(!ptr && 0!==ptr) return undefined;
+ const fi = cache.freeFuncIndexes;
+ const ft = target.functionTable();
+ fi.push(ptr);
+ const rc = ft.get(ptr);
+ ft.set(ptr, null);
+ return rc;
+ };
+
+ /**
+ Given a WASM heap memory address and a data type name in the form
+ (i8, i16, i32, i64, float (or f32), double (or f64)), this
+ fetches the numeric value from that address and returns it as a
+ number or, for the case of type='i64', a BigInt (noting that that
+ type triggers an exception if this.bigIntEnabled is
+ falsy). Throws if given an invalid type.
+
+ If the first argument is an array, it is treated as an array of
+ addresses and the result is an array of the values from each of
+ those address, using the same 2nd argument for determining the
+ value type to fetch.
+
+ As a special case, if type ends with a `*`, it is considered to
+ be a pointer type and is treated as the WASM numeric type
+ appropriate for the pointer size (`i32`).
+
+ While likely not obvious, this routine and its poke()
+ counterpart are how pointer-to-value _output_ parameters
+ in WASM-compiled C code can be interacted with:
+
+ ```
+ const ptr = alloc(4);
+ poke(ptr, 0, 'i32'); // clear the ptr's value
+ aCFuncWithOutputPtrToInt32Arg( ptr ); // e.g. void foo(int *x);
+ const result = peek(ptr, 'i32'); // fetch ptr's value
+ dealloc(ptr);
+ ```
+
+ scopedAlloc() and friends can be used to make handling of
+ `ptr` safe against leaks in the case of an exception:
+
+ ```
+ let result;
+ const scope = scopedAllocPush();
+ try{
+ const ptr = scopedAlloc(4);
+ poke(ptr, 0, 'i32');
+ aCFuncWithOutputPtrArg( ptr );
+ result = peek(ptr, 'i32');
+ }finally{
+ scopedAllocPop(scope);
+ }
+ ```
+
+ As a rule poke() must be called to set (typically zero
+ out) the pointer's value, else it will contain an essentially
+ random value.
+
+ ACHTUNG: calling this often, e.g. in a loop, can have a noticably
+ painful impact on performance. Rather than doing so, use
+ heapForSize() to fetch the heap object and read directly from it.
+
+ See: poke()
+ */
+ target.peek = function f(ptr, type='i8'){
+ if(type.endsWith('*')) type = ptrIR;
+ const c = (cache.memory && cache.heapSize === cache.memory.buffer.byteLength)
+ ? cache : heapWrappers();
+ const list = Array.isArray(ptr) ? [] : undefined;
+ let rc;
+ do{
+ if(list) ptr = arguments[0].shift();
+ switch(type){
+ case 'i1':
+ case 'i8': rc = c.HEAP8[ptr>>0]; break;
+ case 'i16': rc = c.HEAP16[ptr>>1]; break;
+ case 'i32': rc = c.HEAP32[ptr>>2]; break;
+ case 'float': case 'f32': rc = c.HEAP32F[ptr>>2]; break;
+ case 'double': case 'f64': rc = Number(c.HEAP64F[ptr>>3]); break;
+ case 'i64':
+ if(target.bigIntEnabled){
+ rc = BigInt(c.HEAP64[ptr>>3]);
+ break;
+ }
+ /* fallthru */
+ default:
+ toss('Invalid type for peek():',type);
+ }
+ if(list) list.push(rc);
+ }while(list && arguments[0].length);
+ return list || rc;
+ };
+
+ /**
+ The counterpart of peek(), this sets a numeric value at the given
+ WASM heap address, using the 3rd argument to define how many
+ bytes are written. Throws if given an invalid type. See peek()
+ for details about the `type` argument. If the 3rd argument ends
+ with `*` then it is treated as a pointer type and this function
+ behaves as if the 3rd argument were `i32`.
+
+ If the first argument is an array, it is treated like a list
+ of pointers and the given value is written to each one.
+
+ Returns `this`. (Prior to 2022-12-09 it returned this function.)
+
+ ACHTUNG: calling this often, e.g. in a loop to populate a large
+ chunk of memory, can have a noticably painful impact on
+ performance. Rather than doing so, use heapForSize() to fetch the
+ heap object and assign directly to it or use the heap's set()
+ method.
+ */
+ target.poke = function(ptr, value, type='i8'){
+ if (type.endsWith('*')) type = ptrIR;
+ const c = (cache.memory && cache.heapSize === cache.memory.buffer.byteLength)
+ ? cache : heapWrappers();
+ for(const p of (Array.isArray(ptr) ? ptr : [ptr])){
+ switch (type) {
+ case 'i1':
+ case 'i8': c.HEAP8[p>>0] = value; continue;
+ case 'i16': c.HEAP16[p>>1] = value; continue;
+ case 'i32': c.HEAP32[p>>2] = value; continue;
+ case 'float': case 'f32': c.HEAP32F[p>>2] = value; continue;
+ case 'double': case 'f64': c.HEAP64F[p>>3] = value; continue;
+ case 'i64':
+ if(c.HEAP64){
+ c.HEAP64[p>>3] = BigInt(value);
+ continue;
+ }
+ /* fallthru */
+ default:
+ toss('Invalid type for poke(): ' + type);
+ }
+ }
+ return this;
+ };
+
+ /**
+ Convenience form of peek() intended for fetching
+ pointer-to-pointer values. If passed a single non-array argument
+ it returns the value of that one pointer address. If passed
+ multiple arguments, or a single array of arguments, it returns an
+ array of their values.
+ */
+ target.peekPtr = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), ptrIR );
+
+ /**
+ A variant of poke() intended for setting pointer-to-pointer
+ values. Its differences from poke() are that (1) it defaults to a
+ value of 0 and (2) it always writes to the pointer-sized heap
+ view.
+ */
+ target.pokePtr = (ptr, value=0)=>target.poke(ptr, value, ptrIR);
+
+ /**
+ Convenience form of peek() intended for fetching i8 values. If
+ passed a single non-array argument it returns the value of that
+ one pointer address. If passed multiple arguments, or a single
+ array of arguments, it returns an array of their values.
+ */
+ target.peek8 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i8' );
+ /**
+ Convience form of poke() intended for setting individual bytes.
+ Its difference from poke() is that it always writes to the
+ i8-sized heap view.
+ */
+ target.poke8 = (ptr, value)=>target.poke(ptr, value, 'i8');
+ /** i16 variant of peek8(). */
+ target.peek16 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i16' );
+ /** i16 variant of poke8(). */
+ target.poke16 = (ptr, value)=>target.poke(ptr, value, 'i16');
+ /** i32 variant of peek8(). */
+ target.peek32 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i32' );
+ /** i32 variant of poke8(). */
+ target.poke32 = (ptr, value)=>target.poke(ptr, value, 'i32');
+ /** i64 variant of peek8(). Will throw if this build is not
+ configured for BigInt support. */
+ target.peek64 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i64' );
+ /** i64 variant of poke8(). Will throw if this build is not
+ configured for BigInt support. Note that this returns
+ a BigInt-type value, not a Number-type value. */
+ target.poke64 = (ptr, value)=>target.poke(ptr, value, 'i64');
+ /** f32 variant of peek8(). */
+ target.peek32f = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'f32' );
+ /** f32 variant of poke8(). */
+ target.poke32f = (ptr, value)=>target.poke(ptr, value, 'f32');
+ /** f64 variant of peek8(). */
+ target.peek64f = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'f64' );
+ /** f64 variant of poke8(). */
+ target.poke64f = (ptr, value)=>target.poke(ptr, value, 'f64');
+
+ /** Deprecated alias for getMemValue() */
+ target.getMemValue = target.peek;
+ /** Deprecated alias for peekPtr() */
+ target.getPtrValue = target.peekPtr;
+ /** Deprecated alias for poke() */
+ target.setMemValue = target.poke;
+ /** Deprecated alias for pokePtr() */
+ target.setPtrValue = target.pokePtr;
+
+ /**
+ Returns true if the given value appears to be legal for use as
+ a WASM pointer value. Its _range_ of values is not (cannot be)
+ validated except to ensure that it is a 32-bit integer with a
+ value of 0 or greater. Likewise, it cannot verify whether the
+ value actually refers to allocated memory in the WASM heap.
+ */
+ target.isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0);
+
+ /**
+ isPtr() is an alias for isPtr32(). If/when 64-bit WASM pointer
+ support becomes widespread, it will become an alias for either
+ isPtr32() or the as-yet-hypothetical isPtr64(), depending on a
+ configuration option.
+ */
+ target.isPtr = target.isPtr32;
+
+ /**
+ Expects ptr to be a pointer into the WASM heap memory which
+ refers to a NUL-terminated C-style string encoded as UTF-8.
+ Returns the length, in bytes, of the string, as for `strlen(3)`.
+ As a special case, if !ptr or if it's not a pointer then it
+ returns `null`. Throws if ptr is out of range for
+ target.heap8u().
+ */
+ target.cstrlen = function(ptr){
+ if(!ptr || !target.isPtr(ptr)) return null;
+ const h = heapWrappers().HEAP8U;
+ let pos = ptr;
+ for( ; h[pos] !== 0; ++pos ){}
+ return pos - ptr;
+ };
+
+ /** Internal helper to use in operations which need to distinguish
+ between SharedArrayBuffer heap memory and non-shared heap. */
+ const __SAB = ('undefined'===typeof SharedArrayBuffer)
+ ? function(){} : SharedArrayBuffer;
+ const __utf8Decode = function(arrayBuffer, begin, end){
+ return cache.utf8Decoder.decode(
+ (arrayBuffer.buffer instanceof __SAB)
+ ? arrayBuffer.slice(begin, end)
+ : arrayBuffer.subarray(begin, end)
+ );
+ };
+
+ /**
+ Expects ptr to be a pointer into the WASM heap memory which
+ refers to a NUL-terminated C-style string encoded as UTF-8. This
+ function counts its byte length using cstrlen() then returns a
+ JS-format string representing its contents. As a special case, if
+ ptr is falsy or not a pointer, `null` is returned.
+ */
+ target.cstrToJs = function(ptr){
+ const n = target.cstrlen(ptr);
+ return n ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr+n) : (null===n ? n : "");
+ };
+
+ /**
+ Given a JS string, this function returns its UTF-8 length in
+ bytes. Returns null if str is not a string.
+ */
+ target.jstrlen = function(str){
+ /** Attribution: derived from Emscripten's lengthBytesUTF8() */
+ if('string'!==typeof str) return null;
+ const n = str.length;
+ let len = 0;
+ for(let i = 0; i < n; ++i){
+ let u = str.charCodeAt(i);
+ if(u>=0xd800 && u<=0xdfff){
+ u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
+ }
+ if(u<=0x7f) ++len;
+ else if(u<=0x7ff) len += 2;
+ else if(u<=0xffff) len += 3;
+ else len += 4;
+ }
+ return len;
+ };
+
+ /**
+ Encodes the given JS string as UTF8 into the given TypedArray
+ tgt, starting at the given offset and writing, at most, maxBytes
+ bytes (including the NUL terminator if addNul is true, else no
+ NUL is added). If it writes any bytes at all and addNul is true,
+ it always NUL-terminates the output, even if doing so means that
+ the NUL byte is all that it writes.
+
+ If maxBytes is negative (the default) then it is treated as the
+ remaining length of tgt, starting at the given offset.
+
+ If writing the last character would surpass the maxBytes count
+ because the character is multi-byte, that character will not be
+ written (as opposed to writing a truncated multi-byte character).
+ This can lead to it writing as many as 3 fewer bytes than
+ maxBytes specifies.
+
+ Returns the number of bytes written to the target, _including_
+ the NUL terminator (if any). If it returns 0, it wrote nothing at
+ all, which can happen if:
+
+ - str is empty and addNul is false.
+ - offset < 0.
+ - maxBytes == 0.
+ - maxBytes is less than the byte length of a multi-byte str[0].
+
+ Throws if tgt is not an Int8Array or Uint8Array.
+
+ Design notes:
+
+ - In C's strcpy(), the destination pointer is the first
+ argument. That is not the case here primarily because the 3rd+
+ arguments are all referring to the destination, so it seems to
+ make sense to have them grouped with it.
+
+ - Emscripten's counterpart of this function (stringToUTF8Array())
+ returns the number of bytes written sans NUL terminator. That
+ is, however, ambiguous: str.length===0 or maxBytes===(0 or 1)
+ all cause 0 to be returned.
+ */
+ target.jstrcpy = function(jstr, tgt, offset = 0, maxBytes = -1, addNul = true){
+ /** Attribution: the encoding bits are taken from Emscripten's
+ stringToUTF8Array(). */
+ if(!tgt || (!(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array))){
+ toss("jstrcpy() target must be an Int8Array or Uint8Array.");
+ }
+ if(maxBytes<0) maxBytes = tgt.length - offset;
+ if(!(maxBytes>0) || !(offset>=0)) return 0;
+ let i = 0, max = jstr.length;
+ const begin = offset, end = offset + maxBytes - (addNul ? 1 : 0);
+ for(; i < max && offset < end; ++i){
+ let u = jstr.charCodeAt(i);
+ if(u>=0xd800 && u<=0xdfff){
+ u = 0x10000 + ((u & 0x3FF) << 10) | (jstr.charCodeAt(++i) & 0x3FF);
+ }
+ if(u<=0x7f){
+ if(offset >= end) break;
+ tgt[offset++] = u;
+ }else if(u<=0x7ff){
+ if(offset + 1 >= end) break;
+ tgt[offset++] = 0xC0 | (u >> 6);
+ tgt[offset++] = 0x80 | (u & 0x3f);
+ }else if(u<=0xffff){
+ if(offset + 2 >= end) break;
+ tgt[offset++] = 0xe0 | (u >> 12);
+ tgt[offset++] = 0x80 | ((u >> 6) & 0x3f);
+ tgt[offset++] = 0x80 | (u & 0x3f);
+ }else{
+ if(offset + 3 >= end) break;
+ tgt[offset++] = 0xf0 | (u >> 18);
+ tgt[offset++] = 0x80 | ((u >> 12) & 0x3f);
+ tgt[offset++] = 0x80 | ((u >> 6) & 0x3f);
+ tgt[offset++] = 0x80 | (u & 0x3f);
+ }
+ }
+ if(addNul) tgt[offset++] = 0;
+ return offset - begin;
+ };
+
+ /**
+ Works similarly to C's strncpy(), copying, at most, n bytes (not
+ characters) from srcPtr to tgtPtr. It copies until n bytes have
+ been copied or a 0 byte is reached in src. _Unlike_ strncpy(), it
+ returns the number of bytes it assigns in tgtPtr, _including_ the
+ NUL byte (if any). If n is reached before a NUL byte in srcPtr,
+ tgtPtr will _not_ be NULL-terminated. If a NUL byte is reached
+ before n bytes are copied, tgtPtr will be NUL-terminated.
+
+ If n is negative, cstrlen(srcPtr)+1 is used to calculate it, the
+ +1 being for the NUL byte.
+
+ Throws if tgtPtr or srcPtr are falsy. Results are undefined if:
+
+ - either is not a pointer into the WASM heap or
+
+ - srcPtr is not NUL-terminated AND n is less than srcPtr's
+ logical length.
+
+ ACHTUNG: it is possible to copy partial multi-byte characters
+ this way, and converting such strings back to JS strings will
+ have undefined results.
+ */
+ target.cstrncpy = function(tgtPtr, srcPtr, n){
+ if(!tgtPtr || !srcPtr) toss("cstrncpy() does not accept NULL strings.");
+ if(n<0) n = target.cstrlen(strPtr)+1;
+ else if(!(n>0)) return 0;
+ const heap = target.heap8u();
+ let i = 0, ch;
+ for(; i < n && (ch = heap[srcPtr+i]); ++i){
+ heap[tgtPtr+i] = ch;
+ }
+ if(i<n) heap[tgtPtr + i++] = 0;
+ return i;
+ };
+
+ /**
+ For the given JS string, returns a Uint8Array of its contents
+ encoded as UTF-8. If addNul is true, the returned array will have
+ a trailing 0 entry, else it will not.
+ */
+ target.jstrToUintArray = (str, addNul=false)=>{
+ return cache.utf8Encoder.encode(addNul ? (str+"\0") : str);
+ // Or the hard way...
+ /** Attribution: derived from Emscripten's stringToUTF8Array() */
+ //const a = [], max = str.length;
+ //let i = 0, pos = 0;
+ //for(; i < max; ++i){
+ // let u = str.charCodeAt(i);
+ // if(u>=0xd800 && u<=0xdfff){
+ // u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
+ // }
+ // if(u<=0x7f) a[pos++] = u;
+ // else if(u<=0x7ff){
+ // a[pos++] = 0xC0 | (u >> 6);
+ // a[pos++] = 0x80 | (u & 63);
+ // }else if(u<=0xffff){
+ // a[pos++] = 0xe0 | (u >> 12);
+ // a[pos++] = 0x80 | ((u >> 6) & 63);
+ // a[pos++] = 0x80 | (u & 63);
+ // }else{
+ // a[pos++] = 0xf0 | (u >> 18);
+ // a[pos++] = 0x80 | ((u >> 12) & 63);
+ // a[pos++] = 0x80 | ((u >> 6) & 63);
+ // a[pos++] = 0x80 | (u & 63);
+ // }
+ // }
+ // return new Uint8Array(a);
+ };
+
+ const __affirmAlloc = (obj,funcName)=>{
+ if(!(obj.alloc instanceof Function) ||
+ !(obj.dealloc instanceof Function)){
+ toss("Object is missing alloc() and/or dealloc() function(s)",
+ "required by",funcName+"().");
+ }
+ };
+
+ const __allocCStr = function(jstr, returnWithLength, allocator, funcName){
+ __affirmAlloc(target, funcName);
+ if('string'!==typeof jstr) return null;
+ if(0){/* older impl, possibly more widely compatible? */
+ const n = target.jstrlen(jstr),
+ ptr = allocator(n+1);
+ target.jstrcpy(jstr, target.heap8u(), ptr, n+1, true);
+ return returnWithLength ? [ptr, n] : ptr;
+ }else{/* newer, (probably) faster and (certainly) simpler impl */
+ const u = cache.utf8Encoder.encode(jstr),
+ ptr = allocator(u.length+1),
+ heap = heapWrappers().HEAP8U;
+ heap.set(u, ptr);
+ heap[ptr + u.length] = 0;
+ return returnWithLength ? [ptr, u.length] : ptr;
+ }
+ };
+
+ /**
+ Uses target.alloc() to allocate enough memory for jstrlen(jstr)+1
+ bytes of memory, copies jstr to that memory using jstrcpy(),
+ NUL-terminates it, and returns the pointer to that C-string.
+ Ownership of the pointer is transfered to the caller, who must
+ eventually pass the pointer to dealloc() to free it.
+
+ If passed a truthy 2nd argument then its return semantics change:
+ it returns [ptr,n], where ptr is the C-string's pointer and n is
+ its cstrlen().
+
+ Throws if `target.alloc` or `target.dealloc` are not functions.
+ */
+ target.allocCString =
+ (jstr, returnWithLength=false)=>__allocCStr(jstr, returnWithLength,
+ target.alloc, 'allocCString()');
+
+ /**
+ Starts an "allocation scope." All allocations made using
+ scopedAlloc() are recorded in this scope and are freed when the
+ value returned from this function is passed to
+ scopedAllocPop().
+
+ This family of functions requires that the API's object have both
+ `alloc()` and `dealloc()` methods, else this function will throw.
+
+ Intended usage:
+
+ ```
+ const scope = scopedAllocPush();
+ try {
+ const ptr1 = scopedAlloc(100);
+ const ptr2 = scopedAlloc(200);
+ const ptr3 = scopedAlloc(300);
+ ...
+ // Note that only allocations made via scopedAlloc()
+ // are managed by this allocation scope.
+ }finally{
+ scopedAllocPop(scope);
+ }
+ ```
+
+ The value returned by this function must be treated as opaque by
+ the caller, suitable _only_ for passing to scopedAllocPop().
+ Its type and value are not part of this function's API and may
+ change in any given version of this code.
+
+ `scopedAlloc.level` can be used to determine how many scoped
+ alloc levels are currently active.
+ */
+ target.scopedAllocPush = function(){
+ __affirmAlloc(target, 'scopedAllocPush');
+ const a = [];
+ cache.scopedAlloc.push(a);
+ return a;
+ };
+
+ /**
+ Cleans up all allocations made using scopedAlloc() in the context
+ of the given opaque state object, which must be a value returned
+ by scopedAllocPush(). See that function for an example of how to
+ use this function.
+
+ Though scoped allocations are managed like a stack, this API
+ behaves properly if allocation scopes are popped in an order
+ other than the order they were pushed.
+
+ If called with no arguments, it pops the most recent
+ scopedAllocPush() result:
+
+ ```
+ scopedAllocPush();
+ try{ ... } finally { scopedAllocPop(); }
+ ```
+
+ It's generally recommended that it be passed an explicit argument
+ to help ensure that push/push are used in matching pairs, but in
+ trivial code that may be a non-issue.
+ */
+ target.scopedAllocPop = function(state){
+ __affirmAlloc(target, 'scopedAllocPop');
+ const n = arguments.length
+ ? cache.scopedAlloc.indexOf(state)
+ : cache.scopedAlloc.length-1;
+ if(n<0) toss("Invalid state object for scopedAllocPop().");
+ if(0===arguments.length) state = cache.scopedAlloc[n];
+ cache.scopedAlloc.splice(n,1);
+ for(let p; (p = state.pop()); ){
+ if(target.functionEntry(p)){
+ //console.warn("scopedAllocPop() uninstalling function",p);
+ target.uninstallFunction(p);
+ }
+ else target.dealloc(p);
+ }
+ };
+
+ /**
+ Allocates n bytes of memory using this.alloc() and records that
+ fact in the state for the most recent call of scopedAllocPush().
+ Ownership of the memory is given to scopedAllocPop(), which
+ will clean it up when it is called. The memory _must not_ be
+ passed to this.dealloc(). Throws if this API object is missing
+ the required `alloc()` or `dealloc()` functions or no scoped
+ alloc is active.
+
+ See scopedAllocPush() for an example of how to use this function.
+
+ The `level` property of this function can be queried to query how
+ many scoped allocation levels are currently active.
+
+ See also: scopedAllocPtr(), scopedAllocCString()
+ */
+ target.scopedAlloc = function(n){
+ if(!cache.scopedAlloc.length){
+ toss("No scopedAllocPush() scope is active.");
+ }
+ const p = target.alloc(n);
+ cache.scopedAlloc[cache.scopedAlloc.length-1].push(p);
+ return p;
+ };
+
+ Object.defineProperty(target.scopedAlloc, 'level', {
+ configurable: false, enumerable: false,
+ get: ()=>cache.scopedAlloc.length,
+ set: ()=>toss("The 'active' property is read-only.")
+ });
+
+ /**
+ Works identically to allocCString() except that it allocates the
+ memory using scopedAlloc().
+
+ Will throw if no scopedAllocPush() call is active.
+ */
+ target.scopedAllocCString =
+ (jstr, returnWithLength=false)=>__allocCStr(jstr, returnWithLength,
+ target.scopedAlloc, 'scopedAllocCString()');
+
+ // impl for allocMainArgv() and scopedAllocMainArgv().
+ const __allocMainArgv = function(isScoped, list){
+ const pList = target[
+ isScoped ? 'scopedAlloc' : 'alloc'
+ ]((list.length + 1) * target.ptrSizeof);
+ let i = 0;
+ list.forEach((e)=>{
+ target.pokePtr(pList + (target.ptrSizeof * i++),
+ target[
+ isScoped ? 'scopedAllocCString' : 'allocCString'
+ ](""+e));
+ });
+ target.pokePtr(pList + (target.ptrSizeof * i), 0);
+ return pList;
+ };
+
+ /**
+ Creates an array, using scopedAlloc(), suitable for passing to a
+ C-level main() routine. The input is a collection with a length
+ property and a forEach() method. A block of memory
+ (list.length+1) entries long is allocated and each pointer-sized
+ block of that memory is populated with a scopedAllocCString()
+ conversion of the (""+value) of each element, with the exception
+ that the final entry is a NULL pointer. Returns a pointer to the
+ start of the list, suitable for passing as the 2nd argument to a
+ C-style main() function.
+
+ Throws if scopedAllocPush() is not active.
+
+ Design note: the returned array is allocated with an extra NULL
+ pointer entry to accommodate certain APIs, but client code which
+ does not need that functionality should treat the returned array
+ as list.length entries long.
+ */
+ target.scopedAllocMainArgv = (list)=>__allocMainArgv(true, list);
+
+ /**
+ Identical to scopedAllocMainArgv() but uses alloc() instead of
+ scopedAlloc().
+ */
+ target.allocMainArgv = (list)=>__allocMainArgv(false, list);
+
+ /**
+ Expects to be given a C-style string array and its length. It
+ returns a JS array of strings and/or nulls: any entry in the
+ pArgv array which is NULL results in a null entry in the result
+ array. If argc is 0 then an empty array is returned.
+
+ Results are undefined if any entry in the first argc entries of
+ pArgv are neither 0 (NULL) nor legal UTF-format C strings.
+
+ To be clear, the expected C-style arguments to be passed to this
+ function are `(int, char **)` (optionally const-qualified).
+ */
+ target.cArgvToJs = (argc, pArgv)=>{
+ const list = [];
+ for(let i = 0; i < argc; ++i){
+ const arg = target.peekPtr(pArgv + (target.ptrSizeof * i));
+ list.push( arg ? target.cstrToJs(arg) : null );
+ }
+ return list;
+ };
+
+ /**
+ Wraps function call func() in a scopedAllocPush() and
+ scopedAllocPop() block, such that all calls to scopedAlloc() and
+ friends from within that call will have their memory freed
+ automatically when func() returns. If func throws or propagates
+ an exception, the scope is still popped, otherwise it returns the
+ result of calling func().
+ */
+ target.scopedAllocCall = function(func){
+ target.scopedAllocPush();
+ try{ return func() } finally{ target.scopedAllocPop() }
+ };
+
+ /** Internal impl for allocPtr() and scopedAllocPtr(). */
+ const __allocPtr = function(howMany, safePtrSize, method){
+ __affirmAlloc(target, method);
+ const pIr = safePtrSize ? 'i64' : ptrIR;
+ let m = target[method](howMany * (safePtrSize ? 8 : ptrSizeof));
+ target.poke(m, 0, pIr)
+ if(1===howMany){
+ return m;
+ }
+ const a = [m];
+ for(let i = 1; i < howMany; ++i){
+ m += (safePtrSize ? 8 : ptrSizeof);
+ a[i] = m;
+ target.poke(m, 0, pIr);
+ }
+ return a;
+ };
+
+ /**
+ Allocates one or more pointers as a single chunk of memory and
+ zeroes them out.
+
+ The first argument is the number of pointers to allocate. The
+ second specifies whether they should use a "safe" pointer size (8
+ bytes) or whether they may use the default pointer size
+ (typically 4 but also possibly 8).
+
+ How the result is returned depends on its first argument: if
+ passed 1, it returns the allocated memory address. If passed more
+ than one then an array of pointer addresses is returned, which
+ can optionally be used with "destructuring assignment" like this:
+
+ ```
+ const [p1, p2, p3] = allocPtr(3);
+ ```
+
+ ACHTUNG: when freeing the memory, pass only the _first_ result
+ value to dealloc(). The others are part of the same memory chunk
+ and must not be freed separately.
+
+ The reason for the 2nd argument is..
+
+ When one of the returned pointers will refer to a 64-bit value,
+ e.g. a double or int64, an that value must be written or fetched,
+ e.g. using poke() or peek(), it is important that
+ the pointer in question be aligned to an 8-byte boundary or else
+ it will not be fetched or written properly and will corrupt or
+ read neighboring memory. It is only safe to pass false when the
+ client code is certain that it will only get/fetch 4-byte values
+ (or smaller).
+ */
+ target.allocPtr =
+ (howMany=1, safePtrSize=true)=>__allocPtr(howMany, safePtrSize, 'alloc');
+
+ /**
+ Identical to allocPtr() except that it allocates using scopedAlloc()
+ instead of alloc().
+ */
+ target.scopedAllocPtr =
+ (howMany=1, safePtrSize=true)=>__allocPtr(howMany, safePtrSize, 'scopedAlloc');
+
+ /**
+ If target.exports[name] exists, it is returned, else an
+ exception is thrown.
+ */
+ target.xGet = function(name){
+ return target.exports[name] || toss("Cannot find exported symbol:",name);
+ };
+
+ const __argcMismatch =
+ (f,n)=>toss(f+"() requires",n,"argument(s).");
+
+ /**
+ Looks up a WASM-exported function named fname from
+ target.exports. If found, it is called, passed all remaining
+ arguments, and its return value is returned to xCall's caller. If
+ not found, an exception is thrown. This function does no
+ conversion of argument or return types, but see xWrap() and
+ xCallWrapped() for variants which do.
+
+ If the first argument is a function is is assumed to be
+ a WASM-bound function and is used as-is instead of looking up
+ the function via xGet().
+
+ As a special case, if passed only 1 argument after the name and
+ that argument in an Array, that array's entries become the
+ function arguments. (This is not an ambiguous case because it's
+ not legal to pass an Array object to a WASM function.)
+ */
+ target.xCall = function(fname, ...args){
+ const f = (fname instanceof Function) ? fname : target.xGet(fname);
+ if(!(f instanceof Function)) toss("Exported symbol",fname,"is not a function.");
+ if(f.length!==args.length) __argcMismatch(((f===fname) ? f.name : fname),f.length)
+ /* This is arguably over-pedantic but we want to help clients keep
+ from shooting themselves in the foot when calling C APIs. */;
+ return (2===arguments.length && Array.isArray(arguments[1]))
+ ? f.apply(null, arguments[1])
+ : f.apply(null, args);
+ };
+
+ /**
+ State for use with xWrap()
+ */
+ cache.xWrap = Object.create(null);
+ cache.xWrap.convert = Object.create(null);
+ /** Map of type names to argument conversion functions. */
+ cache.xWrap.convert.arg = new Map;
+ /** Map of type names to return result conversion functions. */
+ cache.xWrap.convert.result = new Map;
+ const xArg = cache.xWrap.convert.arg, xResult = cache.xWrap.convert.result;
+
+ if(target.bigIntEnabled){
+ xArg.set('i64', (i)=>BigInt(i));
+ }
+ const __xArgPtr = 'i32' === ptrIR
+ ? ((i)=>(i | 0)) : ((i)=>(BigInt(i) | BigInt(0)));
+ xArg.set('i32', __xArgPtr )
+ .set('i16', (i)=>((i | 0) & 0xFFFF))
+ .set('i8', (i)=>((i | 0) & 0xFF))
+ .set('f32', (i)=>Number(i).valueOf())
+ .set('float', xArg.get('f32'))
+ .set('f64', xArg.get('f32'))
+ .set('double', xArg.get('f64'))
+ .set('int', xArg.get('i32'))
+ .set('null', (i)=>i)
+ .set(null, xArg.get('null'))
+ .set('**', __xArgPtr)
+ .set('*', __xArgPtr);
+ xResult.set('*', __xArgPtr)
+ .set('pointer', __xArgPtr)
+ .set('number', (v)=>Number(v))
+ .set('void', (v)=>undefined)
+ .set('null', (v)=>v)
+ .set(null, xResult.get('null'));
+
+ { /* Copy certain xArg[...] handlers to xResult[...] and
+ add pointer-style variants of them. */
+ const copyToResult = ['i8', 'i16', 'i32', 'int',
+ 'f32', 'float', 'f64', 'double'];
+ if(target.bigIntEnabled) copyToResult.push('i64');
+ const adaptPtr = xArg.get(ptrIR);
+ for(const t of copyToResult){
+ xArg.set(t+'*', adaptPtr);
+ xResult.set(t+'*', adaptPtr);
+ xResult.set(t, (xArg.get(t) || toss("Missing arg converter:",t)));
+ }
+ }
+
+ /**
+ In order for args of type string to work in various contexts in
+ the sqlite3 API, we need to pass them on as, variably, a C-string
+ or a pointer value. Thus for ARGs of type 'string' and
+ '*'/'pointer' we behave differently depending on whether the
+ argument is a string or not:
+
+ - If v is a string, scopeAlloc() a new C-string from it and return
+ that temp string's pointer.
+
+ - Else return the value from the arg adapter defined for ptrIR.
+
+ TODO? Permit an Int8Array/Uint8Array and convert it to a string?
+ Would that be too much magic concentrated in one place, ready to
+ backfire? We handle that at the client level in sqlite3 with a
+ custom argument converter.
+ */
+ const __xArgString = function(v){
+ if('string'===typeof v) return target.scopedAllocCString(v);
+ return v ? __xArgPtr(v) : null;
+ };
+ xArg.set('string', __xArgString)
+ .set('utf8', __xArgString)
+ .set('pointer', __xArgString);
+ //xArg.set('*', __xArgString);
+
+ xResult.set('string', (i)=>target.cstrToJs(i))
+ .set('utf8', xResult.get('string'))
+ .set('string:dealloc', (i)=>{
+ try { return i ? target.cstrToJs(i) : null }
+ finally{ target.dealloc(i) }
+ })
+ .set('utf8:dealloc', xResult.get('string:dealloc'))
+ .set('json', (i)=>JSON.parse(target.cstrToJs(i)))
+ .set('json:dealloc', (i)=>{
+ try{ return i ? JSON.parse(target.cstrToJs(i)) : null }
+ finally{ target.dealloc(i) }
+ });
+
+ /**
+ Internal-use-only base class for FuncPtrAdapter and potentially
+ additional stateful argument adapter classes.
+
+ Note that its main interface (convertArg()) is strictly
+ internal, not to be exposed to client code, as it may still
+ need re-shaping. Only the constructors of concrete subclasses
+ should be exposed to clients, and those in such a way that
+ does not hinder internal redesign of the convertArg()
+ interface.
+ */
+ const AbstractArgAdapter = class {
+ constructor(opt){
+ this.name = opt.name || 'unnamed adapter';
+ }
+ /**
+ Gets called via xWrap() to "convert" v to whatever type
+ this specific class supports.
+
+ argIndex is the argv index of _this_ argument in the
+ being-xWrap()'d call. argv is the current argument list
+ undergoing xWrap() argument conversion. argv entries to the
+ left of argIndex will have already undergone transformation and
+ those to the right will not have (they will have the values the
+ client-level code passed in, awaiting conversion). The RHS
+ indexes must never be relied upon for anything because their
+ types are indeterminate, whereas the LHS values will be
+ WASM-compatible values by the time this is called.
+ */
+ convertArg(v,argv,argIndex){
+ toss("AbstractArgAdapter must be subclassed.");
+ }
+ };
+
+ /**
+ An attempt at adding function pointer conversion support to
+ xWrap(). This type is recognized by xWrap() as a proxy for
+ converting a JS function to a C-side function, either
+ permanently, for the duration of a single call into the C layer,
+ or semi-contextual, where it may keep track of a single binding
+ for a given context and uninstall the binding if it's replaced.
+
+ The constructor requires an options object with these properties:
+
+ - name (optional): string describing the function binding. This
+ is solely for debugging and error-reporting purposes. If not
+ provided, an empty string is assumed.
+
+ - signature: a function signature string compatible with
+ jsFuncToWasm().
+
+ - bindScope (string): one of ('transient', 'context',
+ 'singleton', 'permanent'). Bind scopes are:
+
+ - 'transient': it will convert JS functions to WASM only for
+ the duration of the xWrap()'d function call, using
+ scopedInstallFunction(). Before that call returns, the
+ WASM-side binding will be uninstalled.
+
+ - 'singleton': holds one function-pointer binding for this
+ instance. If it's called with a different function pointer,
+ it uninstalls the previous one after converting the new
+ value. This is only useful for use with "global" functions
+ which do not rely on any state other than this function
+ pointer. If the being-converted function pointer is intended
+ to be mapped to some sort of state object (e.g. an
+ `sqlite3*`) then "context" (see below) is the proper mode.
+
+ - 'context': similar to singleton mode but for a given
+ "context", where the context is a key provided by the user
+ and possibly dependent on a small amount of call-time
+ context. This mode is the default if bindScope is _not_ set
+ but a property named contextKey (described below) is.
+
+ - 'permanent': the function is installed and left there
+ forever. There is no way to recover its pointer address
+ later on.
+
+ - callProxy (function): if set, this must be a function which
+ will act as a proxy for any "converted" JS function. It is
+ passed the being-converted function value and must return
+ either that function or a function which acts on its
+ behalf. The returned function will be the one which gets
+ installed into the WASM function table. The proxy must perform
+ any required argument conversion (noting that it will be called
+ from C code, so will receive C-format arguments) before passing
+ them on to the being-converted function. Whether or not the
+ proxy itself must return a value depends on the context. If it
+ does, it must be a WASM-friendly value, as it will be returning
+ from a call made from native code.
+
+ - contextKey (function): is only used if bindScope is 'context'
+ or if bindScope is not set and this function is, in which case
+ 'context' is assumed. This function gets bound to this object,
+ so its "this" is this object. It gets passed (argv,argIndex),
+ where argIndex is the index of _this_ function pointer in its
+ _wrapping_ function's arguments and argv is the _current_
+ still-being-xWrap()-processed args array. All arguments to the
+ left of argIndex will have been processed by xWrap() by the
+ time this is called. argv[argIndex] will be the value the user
+ passed in to the xWrap()'d function for the argument this
+ FuncPtrAdapter is mapped to. Arguments to the right of
+ argv[argIndex] will not yet have been converted before this is
+ called. The function must return a key which uniquely
+ identifies this function mapping context for _this_
+ FuncPtrAdapter instance (other instances are not considered),
+ taking into account that C functions often take some sort of
+ state object as one or more of their arguments. As an example,
+ if the xWrap()'d function takes `(int,T*,functionPtr,X*)` and
+ this FuncPtrAdapter is the argv[2]nd arg, contextKey(argv,2)
+ might return 'T@'+argv[1], or even just argv[1]. Note,
+ however, that the (X*) argument will not yet have been
+ processed by the time this is called and should not be used as
+ part of that key because its pre-conversion data type might be
+ unpredictable. Similarly, care must be taken with C-string-type
+ arguments: those to the left in argv will, when this is called,
+ be WASM pointers, whereas those to the right might (and likely
+ do) have another data type. When using C-strings in keys, never
+ use their pointers in the key because most C-strings in this
+ constellation are transient.
+
+ Yes, that ^^^ is quite awkward, but it's what we have.
+
+ The constructor only saves the above state for later, and does
+ not actually bind any functions. Its convertArg() method is
+ called via xWrap() to perform any bindings.
+
+ Shortcomings:
+
+ - These "reverse" bindings, i.e. calling into a JS-defined
+ function from a WASM-defined function (the generated proxy
+ wrapper), lack all type conversion support. That means, for
+ example, that...
+
+ - Function pointers which include C-string arguments may still
+ need a level of hand-written wrappers around them, depending on
+ how they're used, in order to provide the client with JS
+ strings. Alternately, clients will need to perform such conversions
+ on their own, e.g. using cstrtojs(). Or maybe we can find a way
+ to perform such conversions here, via addition of an xWrap()-style
+ function signature to the options argument.
+ */
+ xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter {
+ constructor(opt) {
+ super(opt);
+ if(xArg.FuncPtrAdapter.warnOnUse){
+ console.warn('xArg.FuncPtrAdapter is an internal-only API',
+ 'and is not intended to be invoked from',
+ 'client-level code. Invoked with:',opt);
+ }
+ this.name = opt.name || "unnamed";
+ this.signature = opt.signature;
+ if(opt.contextKey instanceof Function){
+ this.contextKey = opt.contextKey;
+ if(!opt.bindScope) opt.bindScope = 'context';
+ }
+ this.bindScope = opt.bindScope
+ || toss("FuncPtrAdapter options requires a bindScope (explicit or implied).");
+ if(FuncPtrAdapter.bindScopes.indexOf(opt.bindScope)<0){
+ toss("Invalid options.bindScope ("+opt.bindMod+") for FuncPtrAdapter. "+
+ "Expecting one of: ("+FuncPtrAdapter.bindScopes.join(', ')+')');
+ }
+ this.isTransient = 'transient'===this.bindScope;
+ this.isContext = 'context'===this.bindScope;
+ this.isPermanent = 'permanent'===this.bindScope;
+ this.singleton = ('singleton'===this.bindScope) ? [] : undefined;
+ //console.warn("FuncPtrAdapter()",opt,this);
+ this.callProxy = (opt.callProxy instanceof Function)
+ ? opt.callProxy : undefined;
+ }
+
+ /**
+ Note that static class members are defined outside of the class
+ to work around an emcc toolchain build problem: one of the
+ tools in emsdk v3.1.42 does not support the static keyword.
+ */
+
+ /* Dummy impl. Overwritten per-instance as needed. */
+ contextKey(argv,argIndex){
+ return this;
+ }
+
+ /* Returns this objects mapping for the given context key, in the
+ form of an an array, creating the mapping if needed. The key
+ may be anything suitable for use in a Map. */
+ contextMap(key){
+ const cm = (this.__cmap || (this.__cmap = new Map));
+ let rc = cm.get(key);
+ if(undefined===rc) cm.set(key, (rc = []));
+ return rc;
+ }
+
+ /**
+ Gets called via xWrap() to "convert" v to a WASM-bound function
+ pointer. If v is one of (a pointer, null, undefined) then
+ (v||0) is returned and any earlier function installed by this
+ mapping _might_, depending on how it's bound, be uninstalled.
+ If v is not one of those types, it must be a Function, for
+ which it creates (if needed) a WASM function binding and
+ returns the WASM pointer to that binding. If this instance is
+ not in 'transient' mode, it will remember the binding for at
+ least the next call, to avoid recreating the function binding
+ unnecessarily.
+
+ If it's passed a pointer(ish) value for v, it does _not_
+ perform any function binding, so this object's bindMode is
+ irrelevant for such cases.
+
+ See the parent class's convertArg() docs for details on what
+ exactly the 2nd and 3rd arguments are.
+ */
+ convertArg(v,argv,argIndex){
+ //FuncPtrAdapter.debugOut("FuncPtrAdapter.convertArg()",this.name,this.signature,this.transient,v);
+ let pair = this.singleton;
+ if(!pair && this.isContext){
+ pair = this.contextMap(this.contextKey(argv,argIndex));
+ //FuncPtrAdapter.debugOut(this.name, this.signature, "contextKey() =",this.contextKey(argv,argIndex), pair);
+ }
+ if(pair && pair[0]===v) return pair[1];
+ if(v instanceof Function){
+ /* Install a WASM binding and return its pointer. */
+ //FuncPtrAdapter.debugOut("FuncPtrAdapter.convertArg()",this.name,this.signature,this.transient,v,pair);
+ if(this.callProxy) v = this.callProxy(v);
+ const fp = __installFunction(v, this.signature, this.isTransient);
+ if(FuncPtrAdapter.debugFuncInstall){
+ FuncPtrAdapter.debugOut("FuncPtrAdapter installed", this,
+ this.contextKey(argv,argIndex), '@'+fp, v);
+ }
+ if(pair){
+ /* Replace existing stashed mapping */
+ if(pair[1]){
+ if(FuncPtrAdapter.debugFuncInstall){
+ FuncPtrAdapter.debugOut("FuncPtrAdapter uninstalling", this,
+ this.contextKey(argv,argIndex), '@'+pair[1], v);
+ }
+ try{
+ /* Because the pending native call might rely on the
+ pointer we're replacing, e.g. as is normally the case
+ with sqlite3's xDestroy() methods, we don't
+ immediately uninstall but instead add its pointer to
+ the scopedAlloc stack, which will be cleared when the
+ xWrap() mechanism is done calling the native
+ function. We're relying very much here on xWrap()
+ having pushed an alloc scope.
+ */
+ cache.scopedAlloc[cache.scopedAlloc.length-1].push(pair[1]);
+ }
+ catch(e){/*ignored*/}
+ }
+ pair[0] = v;
+ pair[1] = fp;
+ }
+ return fp;
+ }else if(target.isPtr(v) || null===v || undefined===v){
+ //FuncPtrAdapter.debugOut("FuncPtrAdapter.convertArg()",this.name,this.signature,this.transient,v,pair);
+ if(pair && pair[1] && pair[1]!==v){
+ /* uninstall stashed mapping and replace stashed mapping with v. */
+ if(FuncPtrAdapter.debugFuncInstall){
+ FuncPtrAdapter.debugOut("FuncPtrAdapter uninstalling", this,
+ this.contextKey(argv,argIndex), '@'+pair[1], v);
+ }
+ try{ cache.scopedAlloc[cache.scopedAlloc.length-1].push(pair[1]) }
+ catch(e){/*ignored*/}
+ pair[0] = pair[1] = (v | 0);
+ }
+ return v || 0;
+ }else{
+ throw new TypeError("Invalid FuncPtrAdapter argument type. "+
+ "Expecting a function pointer or a "+
+ (this.name ? this.name+' ' : '')+
+ "function matching signature "+
+ this.signature+".");
+ }
+ }/*convertArg()*/
+ }/*FuncPtrAdapter*/;
+
+ /** If true, the constructor emits a warning. The intent is that
+ this be set to true after bootstrapping of the higher-level
+ client library is complete, to warn downstream clients that
+ they shouldn't be relying on this implemenation detail which
+ does not have a stable interface. */
+ xArg.FuncPtrAdapter.warnOnUse = false;
+
+ /** If true, convertArg() will FuncPtrAdapter.debugOut() when it
+ (un)installs a function binding to/from WASM. Note that
+ deinstallation of bindScope=transient bindings happens
+ via scopedAllocPop() so will not be output. */
+ xArg.FuncPtrAdapter.debugFuncInstall = false;
+
+ /** Function used for debug output. */
+ xArg.FuncPtrAdapter.debugOut = console.debug.bind(console);
+
+ xArg.FuncPtrAdapter.bindScopes = [
+ 'transient', 'context', 'singleton', 'permanent'
+ ];
+
+ const __xArgAdapterCheck =
+ (t)=>xArg.get(t) || toss("Argument adapter not found:",t);
+
+ const __xResultAdapterCheck =
+ (t)=>xResult.get(t) || toss("Result adapter not found:",t);
+
+ /**
+ Fetches the xWrap() argument adapter mapped to t, calls it,
+ passing in all remaining arguments, and returns the result.
+ Throws if t is not mapped to an argument converter.
+ */
+ cache.xWrap.convertArg = (t,...args)=>__xArgAdapterCheck(t)(...args);
+ /**
+ Identical to convertArg() except that it does not perform
+ an is-defined check on the mapping to t before invoking it.
+ */
+ cache.xWrap.convertArgNoCheck = (t,...args)=>xArg.get(t)(...args);
+
+ /**
+ Fetches the xWrap() result adapter mapped to t, calls it, passing
+ it v, and returns the result. Throws if t is not mapped to an
+ argument converter.
+ */
+ cache.xWrap.convertResult =
+ (t,v)=>(null===t ? v : (t ? __xResultAdapterCheck(t)(v) : undefined));
+ /**
+ Identical to convertResult() except that it does not perform an
+ is-defined check on the mapping to t before invoking it.
+ */
+ cache.xWrap.convertResultNoCheck =
+ (t,v)=>(null===t ? v : (t ? xResult.get(t)(v) : undefined));
+
+ /**
+ Creates a wrapper for another function which converts the arguments
+ of the wrapper to argument types accepted by the wrapped function,
+ then converts the wrapped function's result to another form
+ for the wrapper.
+
+ The first argument must be one of:
+
+ - A JavaScript function.
+ - The name of a WASM-exported function. In the latter case xGet()
+ is used to fetch the exported function, which throws if it's not
+ found.
+ - A pointer into the indirect function table. e.g. a pointer
+ returned from target.installFunction().
+
+ It returns either the passed-in function or a wrapper for that
+ function which converts the JS-side argument types into WASM-side
+ types and converts the result type.
+
+ The second argument, `resultType`, describes the conversion for
+ the wrapped functions result. A literal `null` or the string
+ `'null'` both mean to return the original function's value as-is
+ (mnemonic: there is "null" conversion going on). Literal
+ `undefined` or the string `"void"` both mean to ignore the
+ function's result and return `undefined`. Aside from those two
+ special cases, the `resultType` value may be one of the values
+ described below or any mapping installed by the client using
+ xWrap.resultAdapter().
+
+ If passed 3 arguments and the final one is an array, that array
+ must contain a list of type names (see below) for adapting the
+ arguments from JS to WASM. If passed 2 arguments, more than 3,
+ or the 3rd is not an array, all arguments after the 2nd (if any)
+ are treated as type names. i.e.:
+
+ ```
+ xWrap('funcname', 'i32', 'string', 'f64');
+ // is equivalent to:
+ xWrap('funcname', 'i32', ['string', 'f64']);
+ ```
+
+ This function enforces that the given list of arguments has the
+ same arity as the being-wrapped function (as defined by its
+ `length` property) and it will throw if that is not the case.
+ Similarly, the created wrapper will throw if passed a differing
+ argument count.
+
+ Type names are symbolic names which map the arguments to an
+ adapter function to convert, if needed, the value before passing
+ it on to WASM or to convert a return result from WASM. The list
+ of built-in names:
+
+ - `i8`, `i16`, `i32` (args and results): all integer conversions
+ which convert their argument to an integer and truncate it to
+ the given bit length.
+
+ - `N*` (args): a type name in the form `N*`, where N is a numeric
+ type name, is treated the same as WASM pointer.
+
+ - `*` and `pointer` (args): are assumed to be WASM pointer values
+ and are returned coerced to an appropriately-sized pointer
+ value (i32 or i64). Non-numeric values will coerce to 0 and
+ out-of-range values will have undefined results (just as with
+ any pointer misuse).
+
+ - `*` and `pointer` (results): aliases for the current
+ WASM pointer numeric type.
+
+ - `**` (args): is simply a descriptive alias for the WASM pointer
+ type. It's primarily intended to mark output-pointer arguments.
+
+ - `i64` (args and results): passes the value to BigInt() to
+ convert it to an int64. Only available if bigIntEnabled is
+ true.
+
+ - `f32` (`float`), `f64` (`double`) (args and results): pass
+ their argument to Number(). i.e. the adapter does not currently
+ distinguish between the two types of floating-point numbers.
+
+ - `number` (results): converts the result to a JS Number using
+ Number(theValue).valueOf(). Note that this is for result
+ conversions only, as it's not possible to generically know
+ which type of number to convert arguments to.
+
+ Non-numeric conversions include:
+
+ - `null` literal or `"null"` string (args and results): perform
+ no translation and pass the arg on as-is. This is primarily
+ useful for results but may have a use or two for arguments.
+
+ - `string` or `utf8` (args): has two different semantics in order
+ to accommodate various uses of certain C APIs
+ (e.g. output-style strings)...
+
+ - If the arg is a string, it creates a _temporary_
+ UTF-8-encoded C-string to pass to the exported function,
+ cleaning it up before the wrapper returns. If a long-lived
+ C-string pointer is required, that requires client-side code
+ to create the string, then pass its pointer to the function.
+
+ - Else the arg is assumed to be a pointer to a string the
+ client has already allocated and it's passed on as
+ a WASM pointer.
+
+ - `string` or `utf8` (results): treats the result value as a
+ const C-string, encoded as UTF-8, copies it to a JS string,
+ and returns that JS string.
+
+ - `string:dealloc` or `utf8:dealloc` (results): treats the result
+ value as a non-const UTF-8 C-string, ownership of which has
+ just been transfered to the caller. It copies the C-string to a
+ JS string, frees the C-string, and returns the JS string. If
+ such a result value is NULL, the JS result is `null`. Achtung:
+ when using an API which returns results from a specific
+ allocator, e.g. `my_malloc()`, this conversion _is not
+ legal_. Instead, an equivalent conversion which uses the
+ appropriate deallocator is required. For example:
+
+```js
+ target.xWrap.resultAdapter('string:my_free',(i)=>{
+ try { return i ? target.cstrToJs(i) : null }
+ finally{ target.exports.my_free(i) }
+ };
+```
+
+ - `json` (results): treats the result as a const C-string and
+ returns the result of passing the converted-to-JS string to
+ JSON.parse(). Returns `null` if the C-string is a NULL pointer.
+
+ - `json:dealloc` (results): works exactly like `string:dealloc` but
+ returns the same thing as the `json` adapter. Note the
+ warning in `string:dealloc` regarding maching allocators and
+ deallocators.
+
+ The type names for results and arguments are validated when
+ xWrap() is called and any unknown names will trigger an
+ exception.
+
+ Clients may map their own result and argument adapters using
+ xWrap.resultAdapter() and xWrap.argAdapter(), noting that not all
+ type conversions are valid for both arguments _and_ result types
+ as they often have different memory ownership requirements.
+
+ Design note: the ability to pass in a JS function as the first
+ argument is of relatively limited use, primarily for testing
+ argument and result converters. JS functions, by and large, will
+ not want to deal with C-type arguments.
+
+ TODOs:
+
+ - Figure out how/whether we can (semi-)transparently handle
+ pointer-type _output_ arguments. Those currently require
+ explicit handling by allocating pointers, assigning them before
+ the call using poke(), and fetching them with
+ peek() after the call. We may be able to automate some
+ or all of that.
+
+ - Figure out whether it makes sense to extend the arg adapter
+ interface such that each arg adapter gets an array containing
+ the results of the previous arguments in the current call. That
+ might allow some interesting type-conversion feature. Use case:
+ handling of the final argument to sqlite3_prepare_v2() depends
+ on the type (pointer vs JS string) of its 2nd
+ argument. Currently that distinction requires hand-writing a
+ wrapper for that function. That case is unusual enough that
+ abstracting it into this API (and taking on the associated
+ costs) may well not make good sense.
+ */
+ target.xWrap = function(fArg, resultType, ...argTypes){
+ if(3===arguments.length && Array.isArray(arguments[2])){
+ argTypes = arguments[2];
+ }
+ if(target.isPtr(fArg)){
+ fArg = target.functionEntry(fArg)
+ || toss("Function pointer not found in WASM function table.");
+ }
+ const fIsFunc = (fArg instanceof Function);
+ const xf = fIsFunc ? fArg : target.xGet(fArg);
+ if(fIsFunc) fArg = xf.name || 'unnamed function';
+ if(argTypes.length!==xf.length) __argcMismatch(fArg, xf.length);
+ if((null===resultType) && 0===xf.length){
+ /* Func taking no args with an as-is return. We don't need a wrapper.
+ We forego the argc check here, though. */
+ return xf;
+ }
+ /*Verify the arg type conversions are valid...*/;
+ if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType);
+ for(const t of argTypes){
+ if(t instanceof AbstractArgAdapter) xArg.set(t, (...args)=>t.convertArg(...args));
+ else __xArgAdapterCheck(t);
+ }
+ const cxw = cache.xWrap;
+ if(0===xf.length){
+ // No args to convert, so we can create a simpler wrapper...
+ return (...args)=>(args.length
+ ? __argcMismatch(fArg, xf.length)
+ : cxw.convertResult(resultType, xf.call(null)));
+ }
+ return function(...args){
+ if(args.length!==xf.length) __argcMismatch(fArg, xf.length);
+ const scope = target.scopedAllocPush();
+ try{
+ /*
+ Maintenance reminder re. arguments passed to convertArg():
+ The public interface of argument adapters is that they take
+ ONE argument and return a (possibly) converted result for
+ it. The passing-on of arguments after the first is an
+ internal implementation detail for the sake of
+ AbstractArgAdapter, and not to be relied on or documented
+ for other cases. The fact that this is how
+ AbstractArgAdapter.convertArgs() gets its 2nd+ arguments,
+ and how FuncPtrAdapter.contextKey() gets its args, is also
+ an implementation detail and subject to change. i.e. the
+ public interface of 1 argument is stable. The fact that any
+ arguments may be passed in after that one, and what those
+ arguments are, is _not_ part of the public interface and is
+ _not_ stable.
+
+ Maintenance reminder: the Ember framework modifies the core
+ Array type, breaking for-in loops.
+ */
+ let i = 0;
+ for(; i < args.length; ++i) args[i] = cxw.convertArgNoCheck(
+ argTypes[i], args[i], args, i
+ );
+ return cxw.convertResultNoCheck(resultType, xf.apply(null,args));
+ }finally{
+ target.scopedAllocPop(scope);
+ }
+ };
+ }/*xWrap()*/;
+
+ /** Internal impl for xWrap.resultAdapter() and argAdapter(). */
+ const __xAdapter = function(func, argc, typeName, adapter, modeName, xcvPart){
+ if('string'===typeof typeName){
+ if(1===argc) return xcvPart.get(typeName);
+ else if(2===argc){
+ if(!adapter){
+ delete xcvPart.get(typeName);
+ return func;
+ }else if(!(adapter instanceof Function)){
+ toss(modeName,"requires a function argument.");
+ }
+ xcvPart.set(typeName, adapter);
+ return func;
+ }
+ }
+ toss("Invalid arguments to",modeName);
+ };
+
+ /**
+ Gets, sets, or removes a result value adapter for use with
+ xWrap(). If passed only 1 argument, the adapter function for the
+ given type name is returned. If the second argument is explicit
+ falsy (as opposed to defaulted), the adapter named by the first
+ argument is removed. If the 2nd argument is not falsy, it must be
+ a function which takes one value and returns a value appropriate
+ for the given type name. The adapter may throw if its argument is
+ not of a type it can work with. This function throws for invalid
+ arguments.
+
+ Example:
+
+ ```
+ xWrap.resultAdapter('twice',(v)=>v+v);
+ ```
+
+ xWrap.resultAdapter() MUST NOT use the scopedAlloc() family of
+ APIs to allocate a result value. xWrap()-generated wrappers run
+ in the context of scopedAllocPush() so that argument adapters can
+ easily convert, e.g., to C-strings, and have them cleaned up
+ automatically before the wrapper returns to the caller. Likewise,
+ if a _result_ adapter uses scoped allocation, the result will be
+ freed before because they would be freed before the wrapper
+ returns, leading to chaos and undefined behavior.
+
+ Except when called as a getter, this function returns itself.
+ */
+ target.xWrap.resultAdapter = function f(typeName, adapter){
+ return __xAdapter(f, arguments.length, typeName, adapter,
+ 'resultAdapter()', xResult);
+ };
+
+ /**
+ Functions identically to xWrap.resultAdapter() but applies to
+ call argument conversions instead of result value conversions.
+
+ xWrap()-generated wrappers perform argument conversion in the
+ context of a scopedAllocPush(), so any memory allocation
+ performed by argument adapters really, really, really should be
+ made using the scopedAlloc() family of functions unless
+ specifically necessary. For example:
+
+ ```
+ xWrap.argAdapter('my-string', function(v){
+ return ('string'===typeof v)
+ ? myWasmObj.scopedAllocCString(v) : null;
+ };
+ ```
+
+ Contrariwise, xWrap.resultAdapter() must _not_ use scopedAlloc()
+ to allocate its results because they would be freed before the
+ xWrap()-created wrapper returns.
+
+ Note that it is perfectly legitimate to use these adapters to
+ perform argument validation, as opposed (or in addition) to
+ conversion.
+ */
+ target.xWrap.argAdapter = function f(typeName, adapter){
+ return __xAdapter(f, arguments.length, typeName, adapter,
+ 'argAdapter()', xArg);
+ };
+
+ target.xWrap.FuncPtrAdapter = xArg.FuncPtrAdapter;
+
+ /**
+ Functions like xCall() but performs argument and result type
+ conversions as for xWrap(). The first, second, and third
+ arguments are as documented for xWrap(), except that the 3rd
+ argument may be either a falsy value or empty array to represent
+ nullary functions. The 4th+ arguments are arguments for the call,
+ with the special case that if the 4th argument is an array, it is
+ used as the arguments for the call. Returns the converted result
+ of the call.
+
+ This is just a thin wrapper around xWrap(). If the given function
+ is to be called more than once, it's more efficient to use
+ xWrap() to create a wrapper, then to call that wrapper as many
+ times as needed. For one-shot calls, however, this variant is
+ arguably more efficient because it will hypothetically free the
+ wrapper function quickly.
+ */
+ target.xCallWrapped = function(fArg, resultType, argTypes, ...args){
+ if(Array.isArray(arguments[3])) args = arguments[3];
+ return target.xWrap(fArg, resultType, argTypes||[]).apply(null, args||[]);
+ };
+
+ /**
+ This function is ONLY exposed in the public API to facilitate
+ testing. It should not be used in application-level code, only
+ in test code.
+
+ Expects to be given (typeName, value) and returns a conversion
+ of that value as has been registered using argAdapter().
+ It throws if no adapter is found.
+
+ ACHTUNG: the adapter may require that a scopedAllocPush() is
+ active and it may allocate memory within that scope. It may also
+ require additional arguments, depending on the type of
+ conversion.
+ */
+ target.xWrap.testConvertArg = cache.xWrap.convertArg;
+
+ /**
+ This function is ONLY exposed in the public API to facilitate
+ testing. It should not be used in application-level code, only
+ in test code.
+
+ Expects to be given (typeName, value) and returns a conversion
+ of that value as has been registered using resultAdapter().
+ It throws if no adapter is found.
+
+ ACHTUNG: the adapter may allocate memory which the caller may need
+ to know how to free.
+ */
+ target.xWrap.testConvertResult = cache.xWrap.convertResult;
+
+ return target;
+};
+
+/**
+ yawl (Yet Another Wasm Loader) provides very basic wasm loader.
+ It requires a config object:
+
+ - `uri`: required URI of the WASM file to load.
+
+ - `onload(loadResult,config)`: optional callback. The first
+ argument is the result object from
+ WebAssembly.instantiate[Streaming](). The 2nd is the config
+ object passed to this function. Described in more detail below.
+
+ - `imports`: optional imports object for
+ WebAssembly.instantiate[Streaming](). The default is an empty set
+ of imports. If the module requires any imports, this object
+ must include them.
+
+ - `wasmUtilTarget`: optional object suitable for passing to
+ WhWasmUtilInstaller(). If set, it gets passed to that function
+ after the promise resolves. This function sets several properties
+ on it before passing it on to that function (which sets many
+ more):
+
+ - `module`, `instance`: the properties from the
+ instantiate[Streaming]() result.
+
+ - If `instance.exports.memory` is _not_ set then it requires that
+ `config.imports.env.memory` be set (else it throws), and
+ assigns that to `target.memory`.
+
+ - If `wasmUtilTarget.alloc` is not set and
+ `instance.exports.malloc` is, it installs
+ `wasmUtilTarget.alloc()` and `wasmUtilTarget.dealloc()`
+ wrappers for the exports `malloc` and `free` functions.
+
+ It returns a function which, when called, initiates loading of the
+ module and returns a Promise. When that Promise resolves, it calls
+ the `config.onload` callback (if set) and passes it
+ `(loadResult,config)`, where `loadResult` is the result of
+ WebAssembly.instantiate[Streaming](): an object in the form:
+
+ ```
+ {
+ module: a WebAssembly.Module,
+ instance: a WebAssembly.Instance
+ }
+ ```
+
+ (Note that the initial `then()` attached to the promise gets only
+ that object, and not the `config` one.)
+
+ Error handling is up to the caller, who may attach a `catch()` call
+ to the promise.
+*/
+globalThis.WhWasmUtilInstaller.yawl = function(config){
+ const wfetch = ()=>fetch(config.uri, {credentials: 'same-origin'});
+ const wui = this;
+ const finalThen = function(arg){
+ //log("finalThen()",arg);
+ if(config.wasmUtilTarget){
+ const toss = (...args)=>{throw new Error(args.join(' '))};
+ const tgt = config.wasmUtilTarget;
+ tgt.module = arg.module;
+ tgt.instance = arg.instance;
+ //tgt.exports = tgt.instance.exports;
+ if(!tgt.instance.exports.memory){
+ /**
+ WhWasmUtilInstaller requires either tgt.exports.memory
+ (exported from WASM) or tgt.memory (JS-provided memory
+ imported into WASM).
+ */
+ tgt.memory = (config.imports && config.imports.env
+ && config.imports.env.memory)
+ || toss("Missing 'memory' object!");
+ }
+ if(!tgt.alloc && arg.instance.exports.malloc){
+ const exports = arg.instance.exports;
+ tgt.alloc = function(n){
+ return exports.malloc(n) || toss("Allocation of",n,"bytes failed.");
+ };
+ tgt.dealloc = function(m){exports.free(m)};
+ }
+ wui(tgt);
+ }
+ if(config.onload) config.onload(arg,config);
+ return arg /* for any then() handler attached to
+ yetAnotherWasmLoader()'s return value */;
+ };
+ const loadWasm = WebAssembly.instantiateStreaming
+ ? function loadWasmStreaming(){
+ return WebAssembly.instantiateStreaming(wfetch(), config.imports||{})
+ .then(finalThen);
+ }
+ : function loadWasmOldSchool(){ // Safari < v15
+ return wfetch()
+ .then(response => response.arrayBuffer())
+ .then(bytes => WebAssembly.instantiate(bytes, config.imports||{}))
+ .then(finalThen);
+ };
+ return loadWasm;
+}.bind(globalThis.WhWasmUtilInstaller)/*yawl()*/;
+/* END FILE: common/whwasmutil.js */
+/* BEGIN FILE: jaccwabyt/jaccwabyt.js */
+/**
+ 2022-06-30
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ The Jaccwabyt API is documented in detail in an external file,
+ _possibly_ called jaccwabyt.md in the same directory as this file.
+
+ Project homes:
+ - https://fossil.wanderinghorse.net/r/jaccwabyt
+ - https://sqlite.org/src/dir/ext/wasm/jaccwabyt
+
+*/
+'use strict';
+globalThis.Jaccwabyt = function StructBinderFactory(config){
+/* ^^^^ it is recommended that clients move that object into wherever
+ they'd like to have it and delete the self-held copy ("self" being
+ the global window or worker object). This API does not require the
+ global reference - it is simply installed as a convenience for
+ connecting these bits to other co-developed code before it gets
+ removed from the global namespace.
+*/
+
+ /** Throws a new Error, the message of which is the concatenation
+ all args with a space between each. */
+ const toss = (...args)=>{throw new Error(args.join(' '))};
+
+ /**
+ Implementing function bindings revealed significant
+ shortcomings in Emscripten's addFunction()/removeFunction()
+ interfaces:
+
+ https://github.com/emscripten-core/emscripten/issues/17323
+
+ Until those are resolved, or a suitable replacement can be
+ implemented, our function-binding API will be more limited
+ and/or clumsier to use than initially hoped.
+ */
+ if(!(config.heap instanceof WebAssembly.Memory)
+ && !(config.heap instanceof Function)){
+ toss("config.heap must be WebAssembly.Memory instance or a function.");
+ }
+ ['alloc','dealloc'].forEach(function(k){
+ (config[k] instanceof Function) ||
+ toss("Config option '"+k+"' must be a function.");
+ });
+ const SBF = StructBinderFactory;
+ const heap = (config.heap instanceof Function)
+ ? config.heap : (()=>new Uint8Array(config.heap.buffer)),
+ alloc = config.alloc,
+ dealloc = config.dealloc,
+ log = config.log || console.log.bind(console),
+ memberPrefix = (config.memberPrefix || ""),
+ memberSuffix = (config.memberSuffix || ""),
+ bigIntEnabled = (undefined===config.bigIntEnabled
+ ? !!globalThis['BigInt64Array'] : !!config.bigIntEnabled),
+ BigInt = globalThis['BigInt'],
+ BigInt64Array = globalThis['BigInt64Array'],
+ /* Undocumented (on purpose) config options: */
+ ptrSizeof = config.ptrSizeof || 4,
+ ptrIR = config.ptrIR || 'i32'
+ ;
+
+ if(!SBF.debugFlags){
+ SBF.__makeDebugFlags = function(deriveFrom=null){
+ /* This is disgustingly overengineered. :/ */
+ if(deriveFrom && deriveFrom.__flags) deriveFrom = deriveFrom.__flags;
+ const f = function f(flags){
+ if(0===arguments.length){
+ return f.__flags;
+ }
+ if(flags<0){
+ delete f.__flags.getter; delete f.__flags.setter;
+ delete f.__flags.alloc; delete f.__flags.dealloc;
+ }else{
+ f.__flags.getter = 0!==(0x01 & flags);
+ f.__flags.setter = 0!==(0x02 & flags);
+ f.__flags.alloc = 0!==(0x04 & flags);
+ f.__flags.dealloc = 0!==(0x08 & flags);
+ }
+ return f._flags;
+ };
+ Object.defineProperty(f,'__flags', {
+ iterable: false, writable: false,
+ value: Object.create(deriveFrom)
+ });
+ if(!deriveFrom) f(0);
+ return f;
+ };
+ SBF.debugFlags = SBF.__makeDebugFlags();
+ }/*static init*/
+
+ const isLittleEndian = (function() {
+ const buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
+ // Int16Array uses the platform's endianness.
+ return new Int16Array(buffer)[0] === 256;
+ })();
+ /**
+ Some terms used in the internal docs:
+
+ StructType: a struct-wrapping class generated by this
+ framework.
+ DEF: struct description object.
+ SIG: struct member signature string.
+ */
+
+ /** True if SIG s looks like a function signature, else
+ false. */
+ const isFuncSig = (s)=>'('===s[1];
+ /** True if SIG s is-a pointer signature. */
+ const isPtrSig = (s)=>'p'===s || 'P'===s;
+ const isAutoPtrSig = (s)=>'P'===s /*EXPERIMENTAL*/;
+ const sigLetter = (s)=>isFuncSig(s) ? 'p' : s[0];
+ /** Returns the WASM IR form of the Emscripten-conventional letter
+ at SIG s[0]. Throws for an unknown SIG. */
+ const sigIR = function(s){
+ switch(sigLetter(s)){
+ case 'c': case 'C': return 'i8';
+ case 'i': return 'i32';
+ case 'p': case 'P': case 's': return ptrIR;
+ case 'j': return 'i64';
+ case 'f': return 'float';
+ case 'd': return 'double';
+ }
+ toss("Unhandled signature IR:",s);
+ };
+
+ const affirmBigIntArray = BigInt64Array
+ ? ()=>true : ()=>toss('BigInt64Array is not available.');
+ /** Returns the name of a DataView getter method corresponding
+ to the given SIG. */
+ const sigDVGetter = function(s){
+ switch(sigLetter(s)) {
+ case 'p': case 'P': case 's': {
+ switch(ptrSizeof){
+ case 4: return 'getInt32';
+ case 8: return affirmBigIntArray() && 'getBigInt64';
+ }
+ break;
+ }
+ case 'i': return 'getInt32';
+ case 'c': return 'getInt8';
+ case 'C': return 'getUint8';
+ case 'j': return affirmBigIntArray() && 'getBigInt64';
+ case 'f': return 'getFloat32';
+ case 'd': return 'getFloat64';
+ }
+ toss("Unhandled DataView getter for signature:",s);
+ };
+ /** Returns the name of a DataView setter method corresponding
+ to the given SIG. */
+ const sigDVSetter = function(s){
+ switch(sigLetter(s)){
+ case 'p': case 'P': case 's': {
+ switch(ptrSizeof){
+ case 4: return 'setInt32';
+ case 8: return affirmBigIntArray() && 'setBigInt64';
+ }
+ break;
+ }
+ case 'i': return 'setInt32';
+ case 'c': return 'setInt8';
+ case 'C': return 'setUint8';
+ case 'j': return affirmBigIntArray() && 'setBigInt64';
+ case 'f': return 'setFloat32';
+ case 'd': return 'setFloat64';
+ }
+ toss("Unhandled DataView setter for signature:",s);
+ };
+ /**
+ Returns either Number of BigInt, depending on the given
+ SIG. This constructor is used in property setters to coerce
+ the being-set value to the correct size.
+ */
+ const sigDVSetWrapper = function(s){
+ switch(sigLetter(s)) {
+ case 'i': case 'f': case 'c': case 'C': case 'd': return Number;
+ case 'j': return affirmBigIntArray() && BigInt;
+ case 'p': case 'P': case 's':
+ switch(ptrSizeof){
+ case 4: return Number;
+ case 8: return affirmBigIntArray() && BigInt;
+ }
+ break;
+ }
+ toss("Unhandled DataView set wrapper for signature:",s);
+ };
+
+ /** Returns the given struct and member name in a form suitable for
+ debugging and error output. */
+ const sPropName = (s,k)=>s+'::'+k;
+
+ const __propThrowOnSet = function(structName,propName){
+ return ()=>toss(sPropName(structName,propName),"is read-only.");
+ };
+
+ /**
+ In order to completely hide StructBinder-bound struct
+ pointers from JS code, we store them in a scope-local
+ WeakMap which maps the struct-bound objects to their WASM
+ pointers. The pointers are accessible via
+ boundObject.pointer, which is gated behind an accessor
+ function, but are not exposed anywhere else in the
+ object. The main intention of that is to make it impossible
+ for stale copies to be made.
+ */
+ const __instancePointerMap = new WeakMap();
+
+ /** Property name for the pointer-is-external marker. */
+ const xPtrPropName = '(pointer-is-external)';
+
+ /** Frees the obj.pointer memory and clears the pointer
+ property. */
+ const __freeStruct = function(ctor, obj, m){
+ if(!m) m = __instancePointerMap.get(obj);
+ if(m) {
+ __instancePointerMap.delete(obj);
+ if(Array.isArray(obj.ondispose)){
+ let x;
+ while((x = obj.ondispose.shift())){
+ try{
+ if(x instanceof Function) x.call(obj);
+ else if(x instanceof StructType) x.dispose();
+ else if('number' === typeof x) dealloc(x);
+ // else ignore. Strings are permitted to annotate entries
+ // to assist in debugging.
+ }catch(e){
+ console.warn("ondispose() for",ctor.structName,'@',
+ m,'threw. NOT propagating it.',e);
+ }
+ }
+ }else if(obj.ondispose instanceof Function){
+ try{obj.ondispose()}
+ catch(e){
+ /*do not rethrow: destructors must not throw*/
+ console.warn("ondispose() for",ctor.structName,'@',
+ m,'threw. NOT propagating it.',e);
+ }
+ }
+ delete obj.ondispose;
+ if(ctor.debugFlags.__flags.dealloc){
+ log("debug.dealloc:",(obj[xPtrPropName]?"EXTERNAL":""),
+ ctor.structName,"instance:",
+ ctor.structInfo.sizeof,"bytes @"+m);
+ }
+ if(!obj[xPtrPropName]) dealloc(m);
+ }
+ };
+
+ /** Returns a skeleton for a read-only property accessor wrapping
+ value v. */
+ const rop = (v)=>{return {configurable: false, writable: false,
+ iterable: false, value: v}};
+
+ /** Allocates obj's memory buffer based on the size defined in
+ ctor.structInfo.sizeof. */
+ const __allocStruct = function(ctor, obj, m){
+ let fill = !m;
+ if(m) Object.defineProperty(obj, xPtrPropName, rop(m));
+ else{
+ m = alloc(ctor.structInfo.sizeof);
+ if(!m) toss("Allocation of",ctor.structName,"structure failed.");
+ }
+ try {
+ if(ctor.debugFlags.__flags.alloc){
+ log("debug.alloc:",(fill?"":"EXTERNAL"),
+ ctor.structName,"instance:",
+ ctor.structInfo.sizeof,"bytes @"+m);
+ }
+ if(fill) heap().fill(0, m, m + ctor.structInfo.sizeof);
+ __instancePointerMap.set(obj, m);
+ }catch(e){
+ __freeStruct(ctor, obj, m);
+ throw e;
+ }
+ };
+ /** Gets installed as the memoryDump() method of all structs. */
+ const __memoryDump = function(){
+ const p = this.pointer;
+ return p
+ ? new Uint8Array(heap().slice(p, p+this.structInfo.sizeof))
+ : null;
+ };
+
+ const __memberKey = (k)=>memberPrefix + k + memberSuffix;
+ const __memberKeyProp = rop(__memberKey);
+
+ /**
+ Looks up a struct member in structInfo.members. Throws if found
+ if tossIfNotFound is true, else returns undefined if not
+ found. The given name may be either the name of the
+ structInfo.members key (faster) or the key as modified by the
+ memberPrefix and memberSuffix settings.
+ */
+ const __lookupMember = function(structInfo, memberName, tossIfNotFound=true){
+ let m = structInfo.members[memberName];
+ if(!m && (memberPrefix || memberSuffix)){
+ // Check for a match on members[X].key
+ for(const v of Object.values(structInfo.members)){
+ if(v.key===memberName){ m = v; break; }
+ }
+ if(!m && tossIfNotFound){
+ toss(sPropName(structInfo.name,memberName),'is not a mapped struct member.');
+ }
+ }
+ return m;
+ };
+
+ /**
+ Uses __lookupMember(obj.structInfo,memberName) to find a member,
+ throwing if not found. Returns its signature, either in this
+ framework's native format or in Emscripten format.
+ */
+ const __memberSignature = function f(obj,memberName,emscriptenFormat=false){
+ if(!f._) f._ = (x)=>x.replace(/[^vipPsjrdcC]/g,"").replace(/[pPscC]/g,'i');
+ const m = __lookupMember(obj.structInfo, memberName, true);
+ return emscriptenFormat ? f._(m.signature) : m.signature;
+ };
+
+ const __ptrPropDescriptor = {
+ configurable: false, enumerable: false,
+ get: function(){return __instancePointerMap.get(this)},
+ set: ()=>toss("Cannot assign the 'pointer' property of a struct.")
+ // Reminder: leaving `set` undefined makes assignments
+ // to the property _silently_ do nothing. Current unit tests
+ // rely on it throwing, though.
+ };
+
+ /** Impl of X.memberKeys() for StructType and struct ctors. */
+ const __structMemberKeys = rop(function(){
+ const a = [];
+ for(const k of Object.keys(this.structInfo.members)){
+ a.push(this.memberKey(k));
+ }
+ return a;
+ });
+
+ const __utf8Decoder = new TextDecoder('utf-8');
+ const __utf8Encoder = new TextEncoder();
+ /** Internal helper to use in operations which need to distinguish
+ between SharedArrayBuffer heap memory and non-shared heap. */
+ const __SAB = ('undefined'===typeof SharedArrayBuffer)
+ ? function(){} : SharedArrayBuffer;
+ const __utf8Decode = function(arrayBuffer, begin, end){
+ return __utf8Decoder.decode(
+ (arrayBuffer.buffer instanceof __SAB)
+ ? arrayBuffer.slice(begin, end)
+ : arrayBuffer.subarray(begin, end)
+ );
+ };
+ /**
+ Uses __lookupMember() to find the given obj.structInfo key.
+ Returns that member if it is a string, else returns false. If the
+ member is not found, throws if tossIfNotFound is true, else
+ returns false.
+ */
+ const __memberIsString = function(obj,memberName, tossIfNotFound=false){
+ const m = __lookupMember(obj.structInfo, memberName, tossIfNotFound);
+ return (m && 1===m.signature.length && 's'===m.signature[0]) ? m : false;
+ };
+
+ /**
+ Given a member description object, throws if member.signature is
+ not valid for assigning to or interpretation as a C-style string.
+ It optimistically assumes that any signature of (i,p,s) is
+ C-string compatible.
+ */
+ const __affirmCStringSignature = function(member){
+ if('s'===member.signature) return;
+ toss("Invalid member type signature for C-string value:",
+ JSON.stringify(member));
+ };
+
+ /**
+ Looks up the given member in obj.structInfo. If it has a
+ signature of 's' then it is assumed to be a C-style UTF-8 string
+ and a decoded copy of the string at its address is returned. If
+ the signature is of any other type, it throws. If an s-type
+ member's address is 0, `null` is returned.
+ */
+ const __memberToJsString = function f(obj,memberName){
+ const m = __lookupMember(obj.structInfo, memberName, true);
+ __affirmCStringSignature(m);
+ const addr = obj[m.key];
+ //log("addr =",addr,memberName,"m =",m);
+ if(!addr) return null;
+ let pos = addr;
+ const mem = heap();
+ for( ; mem[pos]!==0; ++pos ) {
+ //log("mem[",pos,"]",mem[pos]);
+ };
+ //log("addr =",addr,"pos =",pos);
+ return (addr===pos) ? "" : __utf8Decode(mem, addr, pos);
+ };
+
+ /**
+ Adds value v to obj.ondispose, creating ondispose,
+ or converting it to an array, if needed.
+ */
+ const __addOnDispose = function(obj, ...v){
+ if(obj.ondispose){
+ if(!Array.isArray(obj.ondispose)){
+ obj.ondispose = [obj.ondispose];
+ }
+ }else{
+ obj.ondispose = [];
+ }
+ obj.ondispose.push(...v);
+ };
+
+ /**
+ Allocates a new UTF-8-encoded, NUL-terminated copy of the given
+ JS string and returns its address relative to heap(). If
+ allocation returns 0 this function throws. Ownership of the
+ memory is transfered to the caller, who must eventually pass it
+ to the configured dealloc() function.
+ */
+ const __allocCString = function(str){
+ const u = __utf8Encoder.encode(str);
+ const mem = alloc(u.length+1);
+ if(!mem) toss("Allocation error while duplicating string:",str);
+ const h = heap();
+ //let i = 0;
+ //for( ; i < u.length; ++i ) h[mem + i] = u[i];
+ h.set(u, mem);
+ h[mem + u.length] = 0;
+ //log("allocCString @",mem," =",u);
+ return mem;
+ };
+
+ /**
+ Sets the given struct member of obj to a dynamically-allocated,
+ UTF-8-encoded, NUL-terminated copy of str. It is up to the caller
+ to free any prior memory, if appropriate. The newly-allocated
+ string is added to obj.ondispose so will be freed when the object
+ is disposed.
+
+ The given name may be either the name of the structInfo.members
+ key (faster) or the key as modified by the memberPrefix and
+ memberSuffix settings.
+ */
+ const __setMemberCString = function(obj, memberName, str){
+ const m = __lookupMember(obj.structInfo, memberName, true);
+ __affirmCStringSignature(m);
+ /* Potential TODO: if obj.ondispose contains obj[m.key] then
+ dealloc that value and clear that ondispose entry */
+ const mem = __allocCString(str);
+ obj[m.key] = mem;
+ __addOnDispose(obj, mem);
+ return obj;
+ };
+
+ /**
+ Prototype for all StructFactory instances (the constructors
+ returned from StructBinder).
+ */
+ const StructType = function ctor(structName, structInfo){
+ if(arguments[2]!==rop){
+ toss("Do not call the StructType constructor",
+ "from client-level code.");
+ }
+ Object.defineProperties(this,{
+ //isA: rop((v)=>v instanceof ctor),
+ structName: rop(structName),
+ structInfo: rop(structInfo)
+ });
+ };
+
+ /**
+ Properties inherited by struct-type-specific StructType instances
+ and (indirectly) concrete struct-type instances.
+ */
+ StructType.prototype = Object.create(null, {
+ dispose: rop(function(){__freeStruct(this.constructor, this)}),
+ lookupMember: rop(function(memberName, tossIfNotFound=true){
+ return __lookupMember(this.structInfo, memberName, tossIfNotFound);
+ }),
+ memberToJsString: rop(function(memberName){
+ return __memberToJsString(this, memberName);
+ }),
+ memberIsString: rop(function(memberName, tossIfNotFound=true){
+ return __memberIsString(this, memberName, tossIfNotFound);
+ }),
+ memberKey: __memberKeyProp,
+ memberKeys: __structMemberKeys,
+ memberSignature: rop(function(memberName, emscriptenFormat=false){
+ return __memberSignature(this, memberName, emscriptenFormat);
+ }),
+ memoryDump: rop(__memoryDump),
+ pointer: __ptrPropDescriptor,
+ setMemberCString: rop(function(memberName, str){
+ return __setMemberCString(this, memberName, str);
+ })
+ });
+ // Function-type non-Property inherited members
+ Object.assign(StructType.prototype,{
+ addOnDispose: function(...v){
+ __addOnDispose(this,...v);
+ return this;
+ }
+ });
+
+ /**
+ "Static" properties for StructType.
+ */
+ Object.defineProperties(StructType, {
+ allocCString: rop(__allocCString),
+ isA: rop((v)=>v instanceof StructType),
+ hasExternalPointer: rop((v)=>(v instanceof StructType) && !!v[xPtrPropName]),
+ memberKey: __memberKeyProp
+ });
+
+ const isNumericValue = (v)=>Number.isFinite(v) || (v instanceof (BigInt || Number));
+
+ /**
+ Pass this a StructBinder-generated prototype, and the struct
+ member description object. It will define property accessors for
+ proto[memberKey] which read from/write to memory in
+ this.pointer. It modifies descr to make certain downstream
+ operations much simpler.
+ */
+ const makeMemberWrapper = function f(ctor,name, descr){
+ if(!f._){
+ /*cache all available getters/setters/set-wrappers for
+ direct reuse in each accessor function. */
+ f._ = {getters: {}, setters: {}, sw:{}};
+ const a = ['i','c','C','p','P','s','f','d','v()'];
+ if(bigIntEnabled) a.push('j');
+ a.forEach(function(v){
+ //const ir = sigIR(v);
+ f._.getters[v] = sigDVGetter(v) /* DataView[MethodName] values for GETTERS */;
+ f._.setters[v] = sigDVSetter(v) /* DataView[MethodName] values for SETTERS */;
+ f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
+ for conversion */;
+ });
+ const rxSig1 = /^[ipPsjfdcC]$/,
+ rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
+ f.sigCheck = function(obj, name, key,sig){
+ if(Object.prototype.hasOwnProperty.call(obj, key)){
+ toss(obj.structName,'already has a property named',key+'.');
+ }
+ rxSig1.test(sig) || rxSig2.test(sig)
+ || toss("Malformed signature for",
+ sPropName(obj.structName,name)+":",sig);
+ };
+ }
+ const key = ctor.memberKey(name);
+ f.sigCheck(ctor.prototype, name, key, descr.signature);
+ descr.key = key;
+ descr.name = name;
+ const sigGlyph = sigLetter(descr.signature);
+ const xPropName = sPropName(ctor.prototype.structName,key);
+ const dbg = ctor.prototype.debugFlags.__flags;
+ /*
+ TODO?: set prototype of descr to an object which can set/fetch
+ its prefered representation, e.g. conversion to string or mapped
+ function. Advantage: we can avoid doing that via if/else if/else
+ in the get/set methods.
+ */
+ const prop = Object.create(null);
+ prop.configurable = false;
+ prop.enumerable = false;
+ prop.get = function(){
+ if(dbg.getter){
+ log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph),
+ xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof);
+ }
+ let rc = (
+ new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof)
+ )[f._.getters[sigGlyph]](0, isLittleEndian);
+ if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
+ return rc;
+ };
+ if(descr.readOnly){
+ prop.set = __propThrowOnSet(ctor.prototype.structName,key);
+ }else{
+ prop.set = function(v){
+ if(dbg.setter){
+ log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph),
+ xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof, v);
+ }
+ if(!this.pointer){
+ toss("Cannot set struct property on disposed instance.");
+ }
+ if(null===v) v = 0;
+ else while(!isNumericValue(v)){
+ if(isAutoPtrSig(descr.signature) && (v instanceof StructType)){
+ // It's a struct instance: let's store its pointer value!
+ v = v.pointer || 0;
+ if(dbg.setter) log("debug.setter:",xPropName,"resolved to",v);
+ break;
+ }
+ toss("Invalid value for pointer-type",xPropName+'.');
+ }
+ (
+ new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof)
+ )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian);
+ };
+ }
+ Object.defineProperty(ctor.prototype, key, prop);
+ }/*makeMemberWrapper*/;
+
+ /**
+ The main factory function which will be returned to the
+ caller.
+ */
+ const StructBinder = function StructBinder(structName, structInfo){
+ if(1===arguments.length){
+ structInfo = structName;
+ structName = structInfo.name;
+ }else if(!structInfo.name){
+ structInfo.name = structName;
+ }
+ if(!structName) toss("Struct name is required.");
+ let lastMember = false;
+ Object.keys(structInfo.members).forEach((k)=>{
+ // Sanity checks of sizeof/offset info...
+ const m = structInfo.members[k];
+ if(!m.sizeof) toss(structName,"member",k,"is missing sizeof.");
+ else if(m.sizeof===1){
+ (m.signature === 'c' || m.signature === 'C') ||
+ toss("Unexpected sizeof==1 member",
+ sPropName(structInfo.name,k),
+ "with signature",m.signature);
+ }else{
+ // sizes and offsets of size-1 members may be odd values, but
+ // others may not.
+ if(0!==(m.sizeof%4)){
+ console.warn("Invalid struct member description =",m,"from",structInfo);
+ toss(structName,"member",k,"sizeof is not aligned. sizeof="+m.sizeof);
+ }
+ if(0!==(m.offset%4)){
+ console.warn("Invalid struct member description =",m,"from",structInfo);
+ toss(structName,"member",k,"offset is not aligned. offset="+m.offset);
+ }
+ }
+ if(!lastMember || lastMember.offset < m.offset) lastMember = m;
+ });
+ if(!lastMember) toss("No member property descriptions found.");
+ else if(structInfo.sizeof < lastMember.offset+lastMember.sizeof){
+ toss("Invalid struct config:",structName,
+ "max member offset ("+lastMember.offset+") ",
+ "extends past end of struct (sizeof="+structInfo.sizeof+").");
+ }
+ const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags));
+ /** Constructor for the StructCtor. */
+ const StructCtor = function StructCtor(externalMemory){
+ if(!(this instanceof StructCtor)){
+ toss("The",structName,"constructor may only be called via 'new'.");
+ }else if(arguments.length){
+ if(externalMemory!==(externalMemory|0) || externalMemory<=0){
+ toss("Invalid pointer value for",structName,"constructor.");
+ }
+ __allocStruct(StructCtor, this, externalMemory);
+ }else{
+ __allocStruct(StructCtor, this);
+ }
+ };
+ Object.defineProperties(StructCtor,{
+ debugFlags: debugFlags,
+ isA: rop((v)=>v instanceof StructCtor),
+ memberKey: __memberKeyProp,
+ memberKeys: __structMemberKeys,
+ methodInfoForKey: rop(function(mKey){
+ }),
+ structInfo: rop(structInfo),
+ structName: rop(structName)
+ });
+ StructCtor.prototype = new StructType(structName, structInfo, rop);
+ Object.defineProperties(StructCtor.prototype,{
+ debugFlags: debugFlags,
+ constructor: rop(StructCtor)
+ /*if we assign StructCtor.prototype and don't do
+ this then StructCtor!==instance.constructor!*/
+ });
+ Object.keys(structInfo.members).forEach(
+ (name)=>makeMemberWrapper(StructCtor, name, structInfo.members[name])
+ );
+ return StructCtor;
+ };
+ StructBinder.StructType = StructType;
+ StructBinder.config = config;
+ StructBinder.allocCString = __allocCString;
+ if(!StructBinder.debugFlags){
+ StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags);
+ }
+ return StructBinder;
+}/*StructBinderFactory*/;
+/* END FILE: jaccwabyt/jaccwabyt.js */
+/* BEGIN FILE: api/sqlite3-api-glue.c-pp.js */
+/*
+ 2022-07-22
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file glues together disparate pieces of JS which are loaded in
+ previous steps of the sqlite3-api.js bootstrapping process:
+ sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
+ initializes the main API pieces so that the downstream components
+ (e.g. sqlite3-api-oo1.js) have all of the infrastructure that they
+ need.
+*/
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ 'use strict';
+ const toss = (...args)=>{throw new Error(args.join(' '))};
+ const toss3 = sqlite3.SQLite3Error.toss;
+ const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
+ globalThis.WhWasmUtilInstaller(wasm);
+ delete globalThis.WhWasmUtilInstaller;
+
+ if(0){
+ /**
+ Please keep this block around as a maintenance reminder
+ that we cannot rely on this type of check.
+
+ This block fails on Safari, per a report at
+ https://sqlite.org/forum/forumpost/e5b20e1feb.
+
+ It turns out that what Safari serves from the indirect function
+ table (e.g. wasm.functionEntry(X)) is anonymous functions which
+ wrap the WASM functions, rather than returning the WASM
+ functions themselves. That means comparison of such functions
+ is useless for determining whether or not we have a specific
+ function from wasm.exports. i.e. if function X is indirection
+ function table entry N then wasm.exports.X is not equal to
+ wasm.functionEntry(N) in Safari, despite being so in the other
+ browsers.
+ */
+ /**
+ Find a mapping for SQLITE_WASM_DEALLOC, which the API
+ guarantees is a WASM pointer to the same underlying function as
+ wasm.dealloc() (noting that wasm.dealloc() is permitted to be a
+ JS wrapper around the WASM function). There is unfortunately no
+ O(1) algorithm for finding this pointer: we have to walk the
+ WASM indirect function table to find it. However, experience
+ indicates that that particular function is always very close to
+ the front of the table (it's been entry #3 in all relevant
+ tests).
+ */
+ const dealloc = wasm.exports[sqlite3.config.deallocExportName];
+ const nFunc = wasm.functionTable().length;
+ let i;
+ for(i = 0; i < nFunc; ++i){
+ const e = wasm.functionEntry(i);
+ if(dealloc === e){
+ capi.SQLITE_WASM_DEALLOC = i;
+ break;
+ }
+ }
+ if(dealloc !== wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
+ toss("Internal error: cannot find function pointer for SQLITE_WASM_DEALLOC.");
+ }
+ }
+
+ /**
+ Signatures for the WASM-exported C-side functions. Each entry
+ is an array with 2+ elements:
+
+ [ "c-side name",
+ "result type" (wasm.xWrap() syntax),
+ [arg types in xWrap() syntax]
+ // ^^^ this needn't strictly be an array: it can be subsequent
+ // elements instead: [x,y,z] is equivalent to x,y,z
+ ]
+
+ Note that support for the API-specific data types in the
+ result/argument type strings gets plugged in at a later phase in
+ the API initialization process.
+ */
+ wasm.bindingSignatures = [
+ // Please keep these sorted by function name!
+ ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
+ /* sqlite3_auto_extension() has a hand-written binding. */
+ /* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
+ bindings to permit more flexible inputs. */
+ ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
+ ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
+ ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
+ ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
+ ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
+ ["sqlite3_bind_parameter_name", "string", "sqlite3_stmt*", "int"],
+ ["sqlite3_bind_pointer", "int",
+ "sqlite3_stmt*", "int", "*", "string:static", "*"],
+ ["sqlite3_busy_handler","int", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ signature: 'i(pi)',
+ contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
+ }),
+ "*"
+ ]],
+ ["sqlite3_busy_timeout","int", "sqlite3*", "int"],
+ /* sqlite3_cancel_auto_extension() has a hand-written binding. */
+ /* sqlite3_close_v2() is implemented by hand to perform some
+ extra work. */
+ ["sqlite3_changes", "int", "sqlite3*"],
+ ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
+ ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/],
+ ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_count", "int", "sqlite3_stmt*"],
+ ["sqlite3_column_decltype", "string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
+ ["sqlite3_commit_hook", "void*", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'sqlite3_commit_hook',
+ signature: 'i(p)',
+ contextKey: (argv)=>argv[0/* sqlite3* */]
+ }),
+ '*'
+ ]],
+ ["sqlite3_compileoption_get", "string", "int"],
+ ["sqlite3_compileoption_used", "int", "string"],
+ ["sqlite3_complete", "int", "string:flexible"],
+ ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
+ /* sqlite3_create_collation() and sqlite3_create_collation_v2()
+ use hand-written bindings to simplify passing of the callback
+ function. */
+ /* sqlite3_create_function(), sqlite3_create_function_v2(), and
+ sqlite3_create_window_function() use hand-written bindings to
+ simplify handling of their function-type arguments. */
+ ["sqlite3_data_count", "int", "sqlite3_stmt*"],
+ ["sqlite3_db_filename", "string", "sqlite3*", "string"],
+ ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
+ ["sqlite3_db_name", "string", "sqlite3*", "int"],
+ ["sqlite3_db_readonly", "int", "sqlite3*", "string"],
+ ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
+ ["sqlite3_errcode", "int", "sqlite3*"],
+ ["sqlite3_errmsg", "string", "sqlite3*"],
+ ["sqlite3_error_offset", "int", "sqlite3*"],
+ ["sqlite3_errstr", "string", "int"],
+ ["sqlite3_exec", "int", [
+ "sqlite3*", "string:flexible",
+ new wasm.xWrap.FuncPtrAdapter({
+ signature: 'i(pipp)',
+ bindScope: 'transient',
+ callProxy: (callback)=>{
+ let aNames;
+ return (pVoid, nCols, pColVals, pColNames)=>{
+ try {
+ const aVals = wasm.cArgvToJs(nCols, pColVals);
+ if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
+ return callback(aVals, aNames) | 0;
+ }catch(e){
+ /* If we set the db error state here, the higher-level
+ exec() call replaces it with its own, so we have no way
+ of reporting the exception message except the console. We
+ must not propagate exceptions through the C API. Though
+ we make an effort to report OOM here, sqlite3_exec()
+ translates that into SQLITE_ABORT as well. */
+ return e.resultCode || capi.SQLITE_ERROR;
+ }
+ }
+ }
+ }),
+ "*", "**"
+ ]],
+ ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
+ ["sqlite3_extended_errcode", "int", "sqlite3*"],
+ ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
+ ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
+ ["sqlite3_finalize", "int", "sqlite3_stmt*"],
+ ["sqlite3_free", undefined,"*"],
+ ["sqlite3_get_autocommit", "int", "sqlite3*"],
+ ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
+ ["sqlite3_initialize", undefined],
+ ["sqlite3_interrupt", undefined, "sqlite3*"],
+ ["sqlite3_is_interrupted", "int", "sqlite3*"],
+ ["sqlite3_keyword_count", "int"],
+ ["sqlite3_keyword_name", "int", ["int", "**", "*"]],
+ ["sqlite3_keyword_check", "int", ["string", "int"]],
+ ["sqlite3_libversion", "string"],
+ ["sqlite3_libversion_number", "int"],
+ ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
+ ["sqlite3_malloc", "*","int"],
+ ["sqlite3_open", "int", "string", "*"],
+ ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
+ /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
+ separately due to us requiring two different sets of semantics
+ for those, depending on how their SQL argument is provided. */
+ /* sqlite3_randomness() uses a hand-written wrapper to extend
+ the range of supported argument types. */
+ ["sqlite3_realloc", "*","*","int"],
+ ["sqlite3_reset", "int", "sqlite3_stmt*"],
+ /* sqlite3_reset_auto_extension() has a hand-written binding. */
+ ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
+ ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"],
+ ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"],
+ ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"],
+ ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"],
+ ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"],
+ ["sqlite3_result_int", undefined, "sqlite3_context*", "int"],
+ ["sqlite3_result_null", undefined, "sqlite3_context*"],
+ ["sqlite3_result_pointer", undefined,
+ "sqlite3_context*", "*", "string:static", "*"],
+ ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
+ ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
+ ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
+ ["sqlite3_rollback_hook", "void*", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'sqlite3_rollback_hook',
+ signature: 'v(p)',
+ contextKey: (argv)=>argv[0/* sqlite3* */]
+ }),
+ '*'
+ ]],
+ ["sqlite3_set_auxdata", undefined, [
+ "sqlite3_context*", "int", "*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xDestroyAuxData',
+ signature: 'v(*)',
+ contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
+ })
+ ]],
+ ["sqlite3_shutdown", undefined],
+ ["sqlite3_sourceid", "string"],
+ ["sqlite3_sql", "string", "sqlite3_stmt*"],
+ ["sqlite3_status", "int", "int", "*", "*", "int"],
+ ["sqlite3_step", "int", "sqlite3_stmt*"],
+ ["sqlite3_stmt_busy", "int", "sqlite3_stmt*"],
+ ["sqlite3_stmt_readonly", "int", "sqlite3_stmt*"],
+ ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"],
+ ["sqlite3_strglob", "int", "string","string"],
+ ["sqlite3_stricmp", "int", "string", "string"],
+ ["sqlite3_strlike", "int", "string", "string","int"],
+ ["sqlite3_strnicmp", "int", "string", "string", "int"],
+ ["sqlite3_table_column_metadata", "int",
+ "sqlite3*", "string", "string", "string",
+ "**", "**", "*", "*", "*"],
+ ["sqlite3_total_changes", "int", "sqlite3*"],
+ ["sqlite3_trace_v2", "int", [
+ "sqlite3*", "int",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'sqlite3_trace_v2::callback',
+ signature: 'i(ippp)',
+ contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
+ }),
+ "*"
+ ]],
+ ["sqlite3_txn_state", "int", ["sqlite3*","string"]],
+ /* Note that sqlite3_uri_...() have very specific requirements for
+ their first C-string arguments, so we cannot perform any value
+ conversion on those. */
+ ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"],
+ ["sqlite3_uri_key", "string", "sqlite3_filename", "int"],
+ ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"],
+ ["sqlite3_user_data","void*", "sqlite3_context*"],
+ ["sqlite3_value_blob", "*", "sqlite3_value*"],
+ ["sqlite3_value_bytes","int", "sqlite3_value*"],
+ ["sqlite3_value_double","f64", "sqlite3_value*"],
+ ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"],
+ ["sqlite3_value_free", undefined, "sqlite3_value*"],
+ ["sqlite3_value_frombind", "int", "sqlite3_value*"],
+ ["sqlite3_value_int","int", "sqlite3_value*"],
+ ["sqlite3_value_nochange", "int", "sqlite3_value*"],
+ ["sqlite3_value_numeric_type", "int", "sqlite3_value*"],
+ ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"],
+ ["sqlite3_value_subtype", "int", "sqlite3_value*"],
+ ["sqlite3_value_text", "string", "sqlite3_value*"],
+ ["sqlite3_value_type", "int", "sqlite3_value*"],
+ ["sqlite3_vfs_find", "*", "string"],
+ ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
+ ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
+ ]/*wasm.bindingSignatures*/;
+
+ if( !!wasm.exports.sqlite3_progress_handler ){
+ wasm.bindingSignatures.push(
+ ["sqlite3_progress_handler", undefined, [
+ "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
+ name: 'xProgressHandler',
+ signature: 'i(p)',
+ bindScope: 'context',
+ contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
+ }), "*"
+ ]]
+ );
+ }
+
+ if( !!wasm.exports.sqlite3_stmt_explain ){
+ wasm.bindingSignatures.push(
+ ["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"],
+ ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"]
+ );
+ }
+
+ if( !!wasm.exports.sqlite3_set_authorizer ){
+ wasm.bindingSignatures.push(
+ ["sqlite3_set_authorizer", "int", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: "sqlite3_set_authorizer::xAuth",
+ signature: "i(pi"+"ssss)",
+ contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
+ callProxy: (callback)=>{
+ return (pV, iCode, s0, s1, s2, s3)=>{
+ try{
+ s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
+ s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
+ return callback(pV, iCode, s0, s1, s2, s3) || 0;
+ }catch(e){
+ return e.resultCode || capi.SQLITE_ERROR;
+ }
+ }
+ }
+ }),
+ "*"/*pUserData*/
+ ]]
+ );
+ }/* sqlite3_set_authorizer() */
+
+ if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
+ /* ^^^ "the problem" is that this is an optional feature and the
+ build-time function-export list does not currently take
+ optional features into account. */
+ wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
+ }
+
+
+ /**
+ Functions which require BigInt (int64) support are separated from
+ the others because we need to conditionally bind them or apply
+ dummy impls, depending on the capabilities of the environment.
+ (That said: we never actually build without BigInt support,
+ and such builds are untested.)
+
+ Note that not all of these functions directly require int64
+ but are only for use with APIs which require int64. For example,
+ the vtab-related functions.
+ */
+ wasm.bindingSignatures.int64 = [
+ ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
+ ["sqlite3_changes64","i64", ["sqlite3*"]],
+ ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
+ ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
+ /* Careful! Short version: de/serialize() are problematic because they
+ might use a different allocator than the user for managing the
+ deserialized block. de/serialize() are ONLY safe to use with
+ sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. Because
+ of this, the canonical builds of sqlite3.wasm/js guarantee that
+ sqlite3.wasm.alloc() and friends use those allocators. Custom builds
+ may not guarantee that, however. */,
+ ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
+ ["sqlite3_malloc64", "*","i64"],
+ ["sqlite3_msize", "i64", "*"],
+ ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
+ ["sqlite3_realloc64", "*","*", "i64"],
+ ["sqlite3_result_int64", undefined, "*", "i64"],
+ ["sqlite3_result_zeroblob64", "int", "*", "i64"],
+ ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
+ ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
+ ["sqlite3_status64", "int", "int", "*", "*", "int"],
+ ["sqlite3_total_changes64", "i64", ["sqlite3*"]],
+ ["sqlite3_update_hook", "*", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'sqlite3_update_hook',
+ signature: "v(iippj)",
+ contextKey: (argv)=>argv[0/* sqlite3* */],
+ callProxy: (callback)=>{
+ return (p,op,z0,z1,rowid)=>{
+ callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
+ };
+ }
+ }),
+ "*"
+ ]],
+ ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
+ ["sqlite3_value_int64","i64", "sqlite3_value*"]
+ ];
+
+ if( wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab ){
+ wasm.bindingSignatures.int64.push(
+ ["sqlite3_create_module", "int",
+ ["sqlite3*","string","sqlite3_module*","*"]],
+ ["sqlite3_create_module_v2", "int",
+ ["sqlite3*","string","sqlite3_module*","*","*"]],
+ ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
+ ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
+ ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
+ ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
+ ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
+ ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
+ ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
+ /*["sqlite3_vtab_config" is variadic and requires a hand-written
+ proxy.] */
+ ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
+ ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
+ ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
+ );
+ }/* virtual table APIs */
+
+ if(wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook){
+ wasm.bindingSignatures.int64.push(
+ ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
+ ["sqlite3_preupdate_count", "int", "sqlite3*"],
+ ["sqlite3_preupdate_depth", "int", "sqlite3*"],
+ ["sqlite3_preupdate_hook", "*", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'sqlite3_preupdate_hook',
+ signature: "v(ppippjj)",
+ contextKey: (argv)=>argv[0/* sqlite3* */],
+ callProxy: (callback)=>{
+ return (p,db,op,zDb,zTbl,iKey1,iKey2)=>{
+ callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl),
+ iKey1, iKey2);
+ };
+ }
+ }),
+ "*"
+ ]],
+ ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]],
+ ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]]
+ );
+ } /* preupdate API */
+
+ // Add session/changeset APIs...
+ if(wasm.bigIntEnabled
+ && !!wasm.exports.sqlite3changegroup_add
+ && !!wasm.exports.sqlite3session_create
+ && !!wasm.exports.sqlite3_preupdate_hook /* required by the session API */){
+ /**
+ FuncPtrAdapter options for session-related callbacks with the
+ native signature "i(ps)". This proxy converts the 2nd argument
+ from a C string to a JS string before passing the arguments on
+ to the client-provided JS callback.
+ */
+ const __ipsProxy = {
+ signature: 'i(ps)',
+ callProxy:(callback)=>{
+ return (p,s)=>{
+ try{return callback(p, wasm.cstrToJs(s)) | 0}
+ catch(e){return e.resultCode || capi.SQLITE_ERROR}
+ }
+ }
+ };
+
+ wasm.bindingSignatures.int64.push(...[
+ ['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']],
+ ['sqlite3changegroup_add_strm', 'int', [
+ 'sqlite3_changegroup*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changegroup_delete', undefined, ['sqlite3_changegroup*']],
+ ['sqlite3changegroup_new', 'int', ['**']],
+ ['sqlite3changegroup_output', 'int', ['sqlite3_changegroup*', 'int*', '**']],
+ ['sqlite3changegroup_output_strm', 'int', [
+ 'sqlite3_changegroup*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_apply', 'int', [
+ 'sqlite3*', 'int', 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_apply_strm', 'int', [
+ 'sqlite3*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_apply_v2', 'int', [
+ 'sqlite3*', 'int', 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*', '**', 'int*', 'int'
+
+ ]],
+ ['sqlite3changeset_apply_v2_strm', 'int', [
+ 'sqlite3*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*', '**', 'int*', 'int'
+ ]],
+ ['sqlite3changeset_concat', 'int', ['int','void*', 'int', 'void*', 'int*', '**']],
+ ['sqlite3changeset_concat_strm', 'int', [
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInputA', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInputB', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_conflict', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
+ ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']],
+ ['sqlite3changeset_fk_conflicts', 'int', ['sqlite3_changeset_iter*', 'int*']],
+ ['sqlite3changeset_invert', 'int', ['int', 'void*', 'int*', '**']],
+ ['sqlite3changeset_invert_strm', 'int', [
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_new', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
+ ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']],
+ ['sqlite3changeset_old', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
+ ['sqlite3changeset_op', 'int', [
+ 'sqlite3_changeset_iter*', '**', 'int*', 'int*','int*'
+ ]],
+ ['sqlite3changeset_pk', 'int', ['sqlite3_changeset_iter*', '**', 'int*']],
+ ['sqlite3changeset_start', 'int', ['**', 'int', '*']],
+ ['sqlite3changeset_start_strm', 'int', [
+ '**',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']],
+ ['sqlite3changeset_start_v2_strm', 'int', [
+ '**',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*', 'int'
+ ]],
+ ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']],
+ ['sqlite3session_changeset', 'int', ['sqlite3_session*', 'int*', '**']],
+ ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']],
+ ['sqlite3session_changeset_strm', 'int', [
+ 'sqlite3_session*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3session_config', 'int', ['int', 'void*']],
+ ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']],
+ //sqlite3session_delete() is bound manually
+ ['sqlite3session_diff', 'int', ['sqlite3_session*', 'string', 'string', '**']],
+ ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']],
+ ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']],
+ ['sqlite3session_isempty', 'int', ['sqlite3_session*']],
+ ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']],
+ ['sqlite3session_object_config', 'int', ['sqlite3_session*', 'int', 'void*']],
+ ['sqlite3session_patchset', 'int', ['sqlite3_session*', '*', '**']],
+ ['sqlite3session_patchset_strm', 'int', [
+ 'sqlite3_session*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3session_table_filter', undefined, [
+ 'sqlite3_session*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', ...__ipsProxy,
+ contextKey: (argv,argIndex)=>argv[0/* (sqlite3_session*) */]
+ }),
+ '*'
+ ]]
+ ]);
+ }/*session/changeset APIs*/
+
+ /**
+ Functions which are intended solely for API-internal use by the
+ WASM components, not client code. These get installed into
+ sqlite3.util. Some of them get exposed to clients via variants
+ in sqlite3_js_...().
+
+ 2024-01-11: these were renamed, with two underscores in the
+ prefix, to ensure that clients do not accidentally depend on
+ them. They have always been documented as internal-use-only, so
+ no clients "should" be depending on the old names.
+ */
+ wasm.bindingSignatures.wasmInternal = [
+ ["sqlite3__wasm_db_reset", "int", "sqlite3*"],
+ ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
+ [/* DO NOT USE. This is deprecated since 2023-08-11 because it can
+ trigger assert() in debug builds when used with file sizes
+ which are not sizes to a multiple of a valid db page size. */
+ "sqlite3__wasm_vfs_create_file", "int", "sqlite3_vfs*","string","*", "int"
+ ],
+ ["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
+ ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"],
+ ["sqlite3__wasm_qfmt_token","string:dealloc", "string","int"]
+ ];
+
+ /**
+ Install JS<->C struct bindings for the non-opaque struct types we
+ need... */
+ sqlite3.StructBinder = globalThis.Jaccwabyt({
+ heap: 0 ? wasm.memory : wasm.heap8u,
+ alloc: wasm.alloc,
+ dealloc: wasm.dealloc,
+ bigIntEnabled: wasm.bigIntEnabled,
+ memberPrefix: /* Never change this: this prefix is baked into any
+ amount of code and client-facing docs. */ '$'
+ });
+ delete globalThis.Jaccwabyt;
+
+ {// wasm.xWrap() bindings...
+
+ /* Convert Arrays and certain TypedArrays to strings for
+ 'string:flexible'-type arguments */
+ const __xString = wasm.xWrap.argAdapter('string');
+ wasm.xWrap.argAdapter(
+ 'string:flexible', (v)=>__xString(util.flexibleString(v))
+ );
+
+ /**
+ The 'string:static' argument adapter treats its argument as
+ either...
+
+ - WASM pointer: assumed to be a long-lived C-string which gets
+ returned as-is.
+
+ - Anything else: gets coerced to a JS string for use as a map
+ key. If a matching entry is found (as described next), it is
+ returned, else wasm.allocCString() is used to create a a new
+ string, map its pointer to (''+v) for the remainder of the
+ application's life, and returns that pointer value for this
+ call and all future calls which are passed a
+ string-equivalent argument.
+
+ Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
+ call for "a static string and preferably a string
+ literal." This converter is used to ensure that the string
+ value seen by those functions is long-lived and behaves as they
+ need it to.
+ */
+ wasm.xWrap.argAdapter(
+ 'string:static',
+ function(v){
+ if(wasm.isPtr(v)) return v;
+ v = ''+v;
+ let rc = this[v];
+ return rc || (this[v] = wasm.allocCString(v));
+ }.bind(Object.create(null))
+ );
+
+ /**
+ Add some descriptive xWrap() aliases for '*' intended to (A)
+ initially improve readability/correctness of
+ wasm.bindingSignatures and (B) provide automatic conversion
+ from higher-level representations, e.g. capi.sqlite3_vfs to
+ `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
+ */
+ const __xArgPtr = wasm.xWrap.argAdapter('*');
+ const nilType = function(){
+ /*a class which no value can ever be an instance of*/
+ };
+ wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
+ ('sqlite3_context*', __xArgPtr)
+ ('sqlite3_value*', __xArgPtr)
+ ('void*', __xArgPtr)
+ ('sqlite3_changegroup*', __xArgPtr)
+ ('sqlite3_changeset_iter*', __xArgPtr)
+ ('sqlite3_session*', __xArgPtr)
+ ('sqlite3_stmt*', (v)=>
+ __xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
+ ? v.pointer : v))
+ ('sqlite3*', (v)=>
+ __xArgPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
+ ? v.pointer : v))
+ /**
+ `sqlite3_vfs*`:
+
+ - v is-a string: use the result of sqlite3_vfs_find(v) but
+ throw if it returns 0.
+ - v is-a capi.sqlite3_vfs: use v.pointer.
+ - Else return the same as the `'*'` argument conversion.
+ */
+ ('sqlite3_vfs*', (v)=>{
+ if('string'===typeof v){
+ /* A NULL sqlite3_vfs pointer will be treated as the default
+ VFS in many contexts. We specifically do not want that
+ behavior here. */
+ return capi.sqlite3_vfs_find(v)
+ || sqlite3.SQLite3Error.toss(
+ capi.SQLITE_NOTFOUND,
+ "Unknown sqlite3_vfs name:", v
+ );
+ }
+ return __xArgPtr((v instanceof (capi.sqlite3_vfs || nilType))
+ ? v.pointer : v);
+ });
+ if( wasm.exports.sqlite3_declare_vtab ){
+ wasm.xWrap.argAdapter('sqlite3_index_info*', (v)=>
+ __xArgPtr((v instanceof (capi.sqlite3_index_info || nilType))
+ ? v.pointer : v))
+ ('sqlite3_module*', (v)=>
+ __xArgPtr((v instanceof (capi.sqlite3_module || nilType))
+ ? v.pointer : v)
+ );
+ }
+
+ const __xRcPtr = wasm.xWrap.resultAdapter('*');
+ wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
+ ('sqlite3_context*', __xRcPtr)
+ ('sqlite3_stmt*', __xRcPtr)
+ ('sqlite3_value*', __xRcPtr)
+ ('sqlite3_vfs*', __xRcPtr)
+ ('void*', __xRcPtr);
+
+ /**
+ Populate api object with sqlite3_...() by binding the "raw" wasm
+ exports into type-converting proxies using wasm.xWrap().
+ */
+ if(0 === wasm.exports.sqlite3_step.length){
+ /* This environment wraps exports in nullary functions, which means
+ we must disable the arg-count validation we otherwise perform
+ on the wrappers. */
+ wasm.xWrap.doArgcCheck = false;
+ sqlite3.config.warn(
+ "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks."
+ );
+ }
+ for(const e of wasm.bindingSignatures){
+ capi[e[0]] = wasm.xWrap.apply(null, e);
+ }
+ for(const e of wasm.bindingSignatures.wasmInternal){
+ util[e[0]] = wasm.xWrap.apply(null, e);
+ }
+
+ /* For C API functions which cannot work properly unless
+ wasm.bigIntEnabled is true, install a bogus impl which throws
+ if called when bigIntEnabled is false. The alternative would be
+ to elide these functions altogether, which seems likely to
+ cause more confusion. */
+ const fI64Disabled = function(fname){
+ return ()=>toss(fname+"() is unavailable due to lack",
+ "of BigInt support in this build.");
+ };
+ for(const e of wasm.bindingSignatures.int64){
+ capi[e[0]] = wasm.bigIntEnabled
+ ? wasm.xWrap.apply(null, e)
+ : fI64Disabled(e[0]);
+ }
+
+ /* There's no need to expose bindingSignatures to clients,
+ implicitly making it part of the public interface. */
+ delete wasm.bindingSignatures;
+
+ if(wasm.exports.sqlite3__wasm_db_error){
+ const __db_err = wasm.xWrap(
+ 'sqlite3__wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
+ );
+ /**
+ Sets the given db's error state. Accepts:
+
+ - (sqlite3*, int code, string msg)
+ - (sqlite3*, Error e [,string msg = ''+e])
+
+ If passed a WasmAllocError, the message is ignored and the
+ result code is SQLITE_NOMEM. If passed any other Error type,
+ the result code defaults to SQLITE_ERROR unless the Error
+ object has a resultCode property, in which case that is used
+ (e.g. SQLite3Error has that). If passed a non-WasmAllocError
+ exception, the message string defaults to theError.message.
+
+ Returns the resulting code. Pass (pDb,0,0) to clear the error
+ state.
+ */
+ util.sqlite3__wasm_db_error = function(pDb, resultCode, message){
+ if(resultCode instanceof sqlite3.WasmAllocError){
+ resultCode = capi.SQLITE_NOMEM;
+ message = 0 /*avoid allocating message string*/;
+ }else if(resultCode instanceof Error){
+ message = message || ''+resultCode;
+ resultCode = (resultCode.resultCode || capi.SQLITE_ERROR);
+ }
+ return pDb ? __db_err(pDb, resultCode, message) : resultCode;
+ };
+ }else{
+ util.sqlite3__wasm_db_error = function(pDb,errCode,msg){
+ console.warn("sqlite3__wasm_db_error() is not exported.",arguments);
+ return errCode;
+ };
+ }
+ }/*xWrap() bindings*/
+
+ {/* Import C-level constants and structs... */
+ const cJson = wasm.xCall('sqlite3__wasm_enum_json');
+ if(!cJson){
+ toss("Maintenance required: increase sqlite3__wasm_enum_json()'s",
+ "static buffer size!");
+ }
+ //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
+ wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
+ // Groups of SQLITE_xyz macros...
+ const defineGroups = ['access', 'authorizer',
+ 'blobFinalizers', 'changeset',
+ 'config', 'dataTypes',
+ 'dbConfig', 'dbStatus',
+ 'encodings', 'fcntl', 'flock', 'ioCap',
+ 'limits', 'openFlags',
+ 'prepareFlags', 'resultCodes',
+ 'sqlite3Status',
+ 'stmtStatus', 'syncFlags',
+ 'trace', 'txnState', 'udfFlags',
+ 'version' ];
+ if(wasm.bigIntEnabled){
+ defineGroups.push('serialize', 'session', 'vtab');
+ }
+ for(const t of defineGroups){
+ for(const e of Object.entries(wasm.ctype[t])){
+ // ^^^ [k,v] there triggers a buggy code transformation via
+ // one of the Emscripten-driven optimizers.
+ capi[e[0]] = e[1];
+ }
+ }
+ if(!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
+ toss("Internal error: cannot resolve exported function",
+ "entry SQLITE_WASM_DEALLOC (=="+capi.SQLITE_WASM_DEALLOC+").");
+ }
+ const __rcMap = Object.create(null);
+ for(const t of ['resultCodes']){
+ for(const e of Object.entries(wasm.ctype[t])){
+ __rcMap[e[1]] = e[0];
+ }
+ }
+ /**
+ For the given integer, returns the SQLITE_xxx result code as a
+ string, or undefined if no such mapping is found.
+ */
+ capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
+ /* Bind all registered C-side structs... */
+ const notThese = Object.assign(Object.create(null),{
+ // For each struct to NOT register, map its name to true:
+ WasmTestStruct: true,
+ /* We unregister the kvvfs VFS from Worker threads below. */
+ sqlite3_kvvfs_methods: !util.isUIThread(),
+ /* sqlite3_index_info and friends require int64: */
+ sqlite3_index_info: !wasm.bigIntEnabled,
+ sqlite3_index_constraint: !wasm.bigIntEnabled,
+ sqlite3_index_orderby: !wasm.bigIntEnabled,
+ sqlite3_index_constraint_usage: !wasm.bigIntEnabled
+ });
+ for(const s of wasm.ctype.structs){
+ if(!notThese[s.name]){
+ capi[s.name] = sqlite3.StructBinder(s);
+ }
+ }
+ if(capi.sqlite3_index_info){
+ /* Move these inner structs into sqlite3_index_info. Binding
+ ** them to WASM requires that we create global-scope structs to
+ ** model them with, but those are no longer needed after we've
+ ** passed them to StructBinder. */
+ for(const k of ['sqlite3_index_constraint',
+ 'sqlite3_index_orderby',
+ 'sqlite3_index_constraint_usage']){
+ capi.sqlite3_index_info[k] = capi[k];
+ delete capi[k];
+ }
+ capi.sqlite3_vtab_config = wasm.xWrap(
+ 'sqlite3__wasm_vtab_config','int',[
+ 'sqlite3*', 'int', 'int']
+ );
+ }/* end vtab-related setup */
+ }/*end C constant and struct imports*/
+
+ /**
+ Internal helper to assist in validating call argument counts in
+ the hand-written sqlite3_xyz() wrappers. We do this only for
+ consistency with non-special-case wrappings.
+ */
+ const __dbArgcMismatch = (pDb,f,n)=>{
+ return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE,
+ f+"() requires "+n+" argument"+
+ (1===n?"":'s')+".");
+ };
+
+ /** Code duplication reducer for functions which take an encoding
+ argument and require SQLITE_UTF8. Sets the db error code to
+ SQLITE_FORMAT, installs a descriptive error message,
+ and returns SQLITE_FORMAT. */
+ const __errEncoding = (pDb)=>{
+ return util.sqlite3__wasm_db_error(
+ pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
+ );
+ };
+
+ /**
+ __dbCleanupMap is infrastructure for recording registration of
+ UDFs and collations so that sqlite3_close_v2() can clean up any
+ automated JS-to-WASM function conversions installed by those.
+ */
+ const __argPDb = (pDb)=>wasm.xWrap.argAdapter('sqlite3*')(pDb);
+ const __argStr = (str)=>wasm.isPtr(str) ? wasm.cstrToJs(str) : str;
+ const __dbCleanupMap = function(
+ pDb, mode/*0=remove, >0=create if needed, <0=do not create if missing*/
+ ){
+ pDb = __argPDb(pDb);
+ let m = this.dbMap.get(pDb);
+ if(!mode){
+ this.dbMap.delete(pDb);
+ return m;
+ }else if(!m && mode>0){
+ this.dbMap.set(pDb, (m = Object.create(null)));
+ }
+ return m;
+ }.bind(Object.assign(Object.create(null),{
+ dbMap: new Map
+ }));
+
+ __dbCleanupMap.addCollation = function(pDb, name){
+ const m = __dbCleanupMap(pDb, 1);
+ if(!m.collation) m.collation = new Set;
+ m.collation.add(__argStr(name).toLowerCase());
+ };
+
+ __dbCleanupMap._addUDF = function(pDb, name, arity, map){
+ /* Map UDF name to a Set of arity values */
+ name = __argStr(name).toLowerCase();
+ let u = map.get(name);
+ if(!u) map.set(name, (u = new Set));
+ u.add((arity<0) ? -1 : arity);
+ };
+
+ __dbCleanupMap.addFunction = function(pDb, name, arity){
+ const m = __dbCleanupMap(pDb, 1);
+ if(!m.udf) m.udf = new Map;
+ this._addUDF(pDb, name, arity, m.udf);
+ };
+
+ if( wasm.exports.sqlite3_create_window_function ){
+ __dbCleanupMap.addWindowFunc = function(pDb, name, arity){
+ const m = __dbCleanupMap(pDb, 1);
+ if(!m.wudf) m.wudf = new Map;
+ this._addUDF(pDb, name, arity, m.wudf);
+ };
+ }
+
+ /**
+ Intended to be called _only_ from sqlite3_close_v2(),
+ passed its non-0 db argument.
+
+ This function frees up certain automatically-installed WASM
+ function bindings which were installed on behalf of the given db,
+ as those may otherwise leak.
+
+ Notable caveat: this is only ever run via
+ sqlite3.capi.sqlite3_close_v2(). If a client, for whatever
+ reason, uses sqlite3.wasm.exports.sqlite3_close_v2() (the
+ function directly exported from WASM), this cleanup will not
+ happen.
+
+ This is not a silver bullet for avoiding automation-related
+ leaks but represents "an honest effort."
+
+ The issue being addressed here is covered at:
+
+ https://sqlite.org/wasm/doc/trunk/api-c-style.md#convert-func-ptr
+ */
+ __dbCleanupMap.cleanup = function(pDb){
+ pDb = __argPDb(pDb);
+ //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
+ /**
+ Installing NULL functions in the C API will remove those
+ bindings. The FuncPtrAdapter which sits between us and the C
+ API will also treat that as an opportunity to
+ wasm.uninstallFunction() any WASM function bindings it has
+ installed for pDb.
+ */
+ const closeArgs = [pDb];
+ for(const name of [
+ 'sqlite3_busy_handler',
+ 'sqlite3_commit_hook',
+ 'sqlite3_preupdate_hook',
+ 'sqlite3_progress_handler',
+ 'sqlite3_rollback_hook',
+ 'sqlite3_set_authorizer',
+ 'sqlite3_trace_v2',
+ 'sqlite3_update_hook'
+ ]) {
+ const x = wasm.exports[name];
+ if( !x ){
+ /* assume it was built without this API */
+ continue;
+ }
+ closeArgs.length = x.length/*==argument count*/
+ /* recall that undefined entries translate to 0 when passed to
+ WASM. */;
+ try{ capi[name](...closeArgs) }
+ catch(e){
+ sqlite3.config.warn("close-time call of",name+"(",closeArgs,") threw:",e);
+ }
+ }
+ const m = __dbCleanupMap(pDb, 0);
+ if(!m) return;
+ if(m.collation){
+ for(const name of m.collation){
+ try{
+ capi.sqlite3_create_collation_v2(
+ pDb, name, capi.SQLITE_UTF8, 0, 0, 0
+ );
+ }catch(e){
+ /*ignored*/
+ }
+ }
+ delete m.collation;
+ }
+ let i;
+ for(i = 0; i < 2; ++i){ /* Clean up UDFs... */
+ const fmap = i ? m.wudf : m.udf;
+ if(!fmap) continue;
+ const func = i
+ ? capi.sqlite3_create_window_function
+ : capi.sqlite3_create_function_v2;
+ for(const e of fmap){
+ const name = e[0], arities = e[1];
+ const fargs = [pDb, name, 0/*arity*/, capi.SQLITE_UTF8, 0, 0, 0, 0, 0];
+ if(i) fargs.push(0);
+ for(const arity of arities){
+ try{ fargs[2] = arity; func.apply(null, fargs); }
+ catch(e){/*ignored*/}
+ }
+ arities.clear();
+ }
+ fmap.clear();
+ }
+ delete m.udf;
+ delete m.wudf;
+ }/*__dbCleanupMap.cleanup()*/;
+
+ {/* Binding of sqlite3_close_v2() */
+ const __sqlite3CloseV2 = wasm.xWrap("sqlite3_close_v2", "int", "sqlite3*");
+ capi.sqlite3_close_v2 = function(pDb){
+ if(1!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1);
+ if(pDb){
+ try{__dbCleanupMap.cleanup(pDb)} catch(e){/*ignored*/}
+ }
+ return __sqlite3CloseV2(pDb);
+ };
+ }/*sqlite3_close_v2()*/
+
+ if(capi.sqlite3session_create){
+ const __sqlite3SessionDelete = wasm.xWrap(
+ 'sqlite3session_delete', undefined, ['sqlite3_session*']
+ );
+ capi.sqlite3session_delete = function(pSession){
+ if(1!==arguments.length){
+ return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1);
+ /* Yes, we're returning a value from a void function. That seems
+ like the lesser evil compared to not maintaining arg-count
+ consistency as we do with other similar bindings. */
+ }
+ else if(pSession){
+ //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = true;
+ capi.sqlite3session_table_filter(pSession, 0, 0);
+ }
+ __sqlite3SessionDelete(pSession);
+ };
+ }
+
+ {/* Bindings for sqlite3_create_collation[_v2]() */
+ // contextKey() impl for wasm.xWrap.FuncPtrAdapter
+ const contextKey = (argv,argIndex)=>{
+ return 'argv['+argIndex+']:'+argv[0/* sqlite3* */]+
+ ':'+wasm.cstrToJs(argv[1/* collation name */]).toLowerCase()
+ };
+ const __sqlite3CreateCollationV2 = wasm.xWrap(
+ 'sqlite3_create_collation_v2', 'int', [
+ 'sqlite3*', 'string', 'int', '*',
+ new wasm.xWrap.FuncPtrAdapter({
+ /* int(*xCompare)(void*,int,const void*,int,const void*) */
+ name: 'xCompare', signature: 'i(pipip)', contextKey
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ /* void(*xDestroy(void*) */
+ name: 'xDestroy', signature: 'v(p)', contextKey
+ })
+ ]
+ );
+
+ /**
+ Works exactly like C's sqlite3_create_collation_v2() except that:
+
+ 1) It returns capi.SQLITE_FORMAT if the 3rd argument contains
+ any encoding-related value other than capi.SQLITE_UTF8. No
+ other encodings are supported. As a special case, if the
+ bottom 4 bits of that argument are 0, SQLITE_UTF8 is
+ assumed.
+
+ 2) It accepts JS functions for its function-pointer arguments,
+ for which it will install WASM-bound proxies. The bindings
+ are "permanent," in that they will stay in the WASM environment
+ until it shuts down unless the client calls this again with the
+ same collation name and a value of 0 or null for the
+ the function pointer(s).
+
+ For consistency with the C API, it requires the same number of
+ arguments. It returns capi.SQLITE_MISUSE if passed any other
+ argument count.
+
+ Returns 0 on success, non-0 on error, in which case the error
+ state of pDb (of type `sqlite3*` or argument-convertible to it)
+ may contain more information.
+ */
+ capi.sqlite3_create_collation_v2 = function(pDb,zName,eTextRep,pArg,xCompare,xDestroy){
+ if(6!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6);
+ else if( 0 === (eTextRep & 0xf) ){
+ eTextRep |= capi.SQLITE_UTF8;
+ }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
+ return __errEncoding(pDb);
+ }
+ try{
+ const rc = __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
+ if(0===rc && xCompare instanceof Function){
+ __dbCleanupMap.addCollation(pDb, zName);
+ }
+ return rc;
+ }catch(e){
+ return util.sqlite3__wasm_db_error(pDb, e);
+ }
+ };
+
+ capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
+ return (5===arguments.length)
+ ? capi.sqlite3_create_collation_v2(pDb,zName,eTextRep,pArg,xCompare,0)
+ : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5);
+ };
+
+ }/*sqlite3_create_collation() and friends*/
+
+ {/* Special-case handling of sqlite3_create_function_v2()
+ and sqlite3_create_window_function(). */
+ /** FuncPtrAdapter for contextKey() for sqlite3_create_function()
+ and friends. */
+ const contextKey = function(argv,argIndex){
+ return (
+ argv[0/* sqlite3* */]
+ +':'+(argv[2/*number of UDF args*/] < 0 ? -1 : argv[2])
+ +':'+argIndex/*distinct for each xAbc callback type*/
+ +':'+wasm.cstrToJs(argv[1]).toLowerCase()
+ )
+ };
+
+ /**
+ JS proxies for the various sqlite3_create[_window]_function()
+ callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
+ */
+ const __cfProxy = Object.assign(Object.create(null), {
+ xInverseAndStep: {
+ signature:'v(pip)', contextKey,
+ callProxy: (callback)=>{
+ return (pCtx, argc, pArgv)=>{
+ try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
+ catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
+ };
+ }
+ },
+ xFinalAndValue: {
+ signature:'v(p)', contextKey,
+ callProxy: (callback)=>{
+ return (pCtx)=>{
+ try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
+ catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
+ };
+ }
+ },
+ xFunc: {
+ signature:'v(pip)', contextKey,
+ callProxy: (callback)=>{
+ return (pCtx, argc, pArgv)=>{
+ try{
+ capi.sqlite3_result_js(
+ pCtx,
+ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
+ );
+ }catch(e){
+ //console.error('xFunc() caught:',e);
+ capi.sqlite3_result_error_js(pCtx, e);
+ }
+ };
+ }
+ },
+ xDestroy: {
+ signature:'v(p)', contextKey,
+ //Arguable: a well-behaved destructor doesn't require a proxy.
+ callProxy: (callback)=>{
+ return (pVoid)=>{
+ try{ callback(pVoid) }
+ catch(e){ console.error("UDF xDestroy method threw:",e) }
+ };
+ }
+ }
+ })/*__cfProxy*/;
+
+ const __sqlite3CreateFunction = wasm.xWrap(
+ "sqlite3_create_function_v2", "int", [
+ "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
+ "int"/*eTextRep*/, "*"/*pApp*/,
+ new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
+ ]
+ );
+
+ const __sqlite3CreateWindowFunction =
+ wasm.exports.sqlite3_create_window_function
+ ? wasm.xWrap(
+ "sqlite3_create_window_function", "int", [
+ "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
+ "int"/*eTextRep*/, "*"/*pApp*/,
+ new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xValue', ...__cfProxy.xFinalAndValue}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xInverse', ...__cfProxy.xInverseAndStep}),
+ new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
+ ]
+ )
+ : undefined;
+
+ /* Documented in the api object's initializer. */
+ capi.sqlite3_create_function_v2 = function f(
+ pDb, funcName, nArg, eTextRep, pApp,
+ xFunc, //void (*xFunc)(sqlite3_context*,int,sqlite3_value**)
+ xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
+ xFinal, //void (*xFinal)(sqlite3_context*)
+ xDestroy //void (*xDestroy)(void*)
+ ){
+ if( f.length!==arguments.length ){
+ return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length);
+ }else if( 0 === (eTextRep & 0xf) ){
+ eTextRep |= capi.SQLITE_UTF8;
+ }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
+ return __errEncoding(pDb);
+ }
+ try{
+ const rc = __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
+ pApp, xFunc, xStep, xFinal, xDestroy);
+ if(0===rc && (xFunc instanceof Function
+ || xStep instanceof Function
+ || xFinal instanceof Function
+ || xDestroy instanceof Function)){
+ __dbCleanupMap.addFunction(pDb, funcName, nArg);
+ }
+ return rc;
+ }catch(e){
+ console.error("sqlite3_create_function_v2() setup threw:",e);
+ return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
+ }
+ };
+
+ /* Documented in the api object's initializer. */
+ capi.sqlite3_create_function = function f(
+ pDb, funcName, nArg, eTextRep, pApp,
+ xFunc, xStep, xFinal
+ ){
+ return (f.length===arguments.length)
+ ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep,
+ pApp, xFunc, xStep, xFinal, 0)
+ : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length);
+ };
+
+ /* Documented in the api object's initializer. */
+ if( __sqlite3CreateWindowFunction ){
+ capi.sqlite3_create_window_function = function f(
+ pDb, funcName, nArg, eTextRep, pApp,
+ xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
+ xFinal, //void (*xFinal)(sqlite3_context*)
+ xValue, //void (*xValue)(sqlite3_context*)
+ xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**)
+ xDestroy //void (*xDestroy)(void*)
+ ){
+ if( f.length!==arguments.length ){
+ return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length);
+ }else if( 0 === (eTextRep & 0xf) ){
+ eTextRep |= capi.SQLITE_UTF8;
+ }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
+ return __errEncoding(pDb);
+ }
+ try{
+ const rc = __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
+ pApp, xStep, xFinal, xValue,
+ xInverse, xDestroy);
+ if(0===rc && (xStep instanceof Function
+ || xFinal instanceof Function
+ || xValue instanceof Function
+ || xInverse instanceof Function
+ || xDestroy instanceof Function)){
+ __dbCleanupMap.addWindowFunc(pDb, funcName, nArg);
+ }
+ return rc;
+ }catch(e){
+ console.error("sqlite3_create_window_function() setup threw:",e);
+ return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
+ }
+ };
+ }else{
+ delete capi.sqlite3_create_window_function;
+ }
+ /**
+ A _deprecated_ alias for capi.sqlite3_result_js() which
+ predates the addition of that function in the public API.
+ */
+ capi.sqlite3_create_function_v2.udfSetResult =
+ capi.sqlite3_create_function.udfSetResult = capi.sqlite3_result_js;
+ if(capi.sqlite3_create_window_function){
+ capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js;
+ }
+
+ /**
+ A _deprecated_ alias for capi.sqlite3_values_to_js() which
+ predates the addition of that function in the public API.
+ */
+ capi.sqlite3_create_function_v2.udfConvertArgs =
+ capi.sqlite3_create_function.udfConvertArgs = capi.sqlite3_values_to_js;
+ if(capi.sqlite3_create_window_function){
+ capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js;
+ }
+
+ /**
+ A _deprecated_ alias for capi.sqlite3_result_error_js() which
+ predates the addition of that function in the public API.
+ */
+ capi.sqlite3_create_function_v2.udfSetError =
+ capi.sqlite3_create_function.udfSetError = capi.sqlite3_result_error_js;
+ if(capi.sqlite3_create_window_function){
+ capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js;
+ }
+
+ }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
+
+ {/* Special-case handling of sqlite3_prepare_v2() and
+ sqlite3_prepare_v3() */
+
+ /**
+ Helper for string:flexible conversions which require a
+ byte-length counterpart argument. Passed a value and its
+ ostensible length, this function returns [V,N], where V is
+ either v or a transformed copy of v and N is either n, -1, or
+ the byte length of v (if it's a byte array or ArrayBuffer).
+ */
+ const __flexiString = (v,n)=>{
+ if('string'===typeof v){
+ n = -1;
+ }else if(util.isSQLableTypedArray(v)){
+ n = v.byteLength;
+ v = util.typedArrayToString(
+ (v instanceof ArrayBuffer) ? new Uint8Array(v) : v
+ );
+ }else if(Array.isArray(v)){
+ v = v.join("");
+ n = -1;
+ }
+ return [v, n];
+ };
+
+ /**
+ Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
+ */
+ const __prepare = {
+ /**
+ This binding expects a JS string as its 2nd argument and
+ null as its final argument. In order to compile multiple
+ statements from a single string, the "full" impl (see
+ below) must be used.
+ */
+ basic: wasm.xWrap('sqlite3_prepare_v3',
+ "int", ["sqlite3*", "string",
+ "int"/*ignored for this impl!*/,
+ "int", "**",
+ "**"/*MUST be 0 or null or undefined!*/]),
+ /**
+ Impl which requires that the 2nd argument be a pointer
+ to the SQL string, instead of being converted to a
+ string. This variant is necessary for cases where we
+ require a non-NULL value for the final argument
+ (exec()'ing multiple statements from one input
+ string). For simpler cases, where only the first
+ statement in the SQL string is required, the wrapper
+ named sqlite3_prepare_v2() is sufficient and easier to
+ use because it doesn't require dealing with pointers.
+ */
+ full: wasm.xWrap('sqlite3_prepare_v3',
+ "int", ["sqlite3*", "*", "int", "int",
+ "**", "**"])
+ };
+
+ /* Documented in the capi object's initializer. */
+ capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
+ }
+ const [xSql, xSqlLen] = __flexiString(sql, sqlLen);
+ switch(typeof xSql){
+ case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
+ case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
+ default:
+ return util.sqlite3__wasm_db_error(
+ pDb, capi.SQLITE_MISUSE,
+ "Invalid SQL argument type for sqlite3_prepare_v2/v3()."
+ );
+ }
+ };
+
+ /* Documented in the capi object's initializer. */
+ capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){
+ return (f.length===arguments.length)
+ ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
+ : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
+ };
+
+ }/*sqlite3_prepare_v2/v3()*/
+
+ {/*sqlite3_bind_text/blob()*/
+ const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [
+ "sqlite3_stmt*", "int", "string", "int", "*"
+ ]);
+ const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [
+ "sqlite3_stmt*", "int", "*", "int", "*"
+ ]);
+
+ /** Documented in the capi object's initializer. */
+ capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
+ "sqlite3_bind_text", f.length);
+ }else if(wasm.isPtr(text) || null===text){
+ return __bindText(pStmt, iCol, text, nText, xDestroy);
+ }else if(text instanceof ArrayBuffer){
+ text = new Uint8Array(text);
+ }else if(Array.isArray(pMem)){
+ text = pMem.join('');
+ }
+ let p, n;
+ try{
+ if(util.isSQLableTypedArray(text)){
+ p = wasm.allocFromTypedArray(text);
+ n = text.byteLength;
+ }else if('string'===typeof text){
+ [p, n] = wasm.allocCString(text);
+ }else{
+ return util.sqlite3__wasm_db_error(
+ capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
+ "Invalid 3rd argument type for sqlite3_bind_text()."
+ );
+ }
+ return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
+ }catch(e){
+ wasm.dealloc(p);
+ return util.sqlite3__wasm_db_error(
+ capi.sqlite3_db_handle(pStmt), e
+ );
+ }
+ }/*sqlite3_bind_text()*/;
+
+ /** Documented in the capi object's initializer. */
+ capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
+ "sqlite3_bind_blob", f.length);
+ }else if(wasm.isPtr(pMem) || null===pMem){
+ return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy);
+ }else if(pMem instanceof ArrayBuffer){
+ pMem = new Uint8Array(pMem);
+ }else if(Array.isArray(pMem)){
+ pMem = pMem.join('');
+ }
+ let p, n;
+ try{
+ if(util.isBindableTypedArray(pMem)){
+ p = wasm.allocFromTypedArray(pMem);
+ n = nMem>=0 ? nMem : pMem.byteLength;
+ }else if('string'===typeof pMem){
+ [p, n] = wasm.allocCString(pMem);
+ }else{
+ return util.sqlite3__wasm_db_error(
+ capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
+ "Invalid 3rd argument type for sqlite3_bind_blob()."
+ );
+ }
+ return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
+ }catch(e){
+ wasm.dealloc(p);
+ return util.sqlite3__wasm_db_error(
+ capi.sqlite3_db_handle(pStmt), e
+ );
+ }
+ }/*sqlite3_bind_blob()*/;
+
+ }/*sqlite3_bind_text/blob()*/
+
+ {/* sqlite3_config() */
+ /**
+ Wraps a small subset of the C API's sqlite3_config() options.
+ Unsupported options trigger the return of capi.SQLITE_NOTFOUND.
+ Passing fewer than 2 arguments triggers return of
+ capi.SQLITE_MISUSE.
+ */
+ capi.sqlite3_config = function(op, ...args){
+ if(arguments.length<2) return capi.SQLITE_MISUSE;
+ switch(op){
+ case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: // 20 /* int */
+ case capi.SQLITE_CONFIG_MEMSTATUS:// 9 /* boolean */
+ case capi.SQLITE_CONFIG_SMALL_MALLOC: // 27 /* boolean */
+ case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28 /* int nByte */
+ case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26 /* int nByte */
+ case capi.SQLITE_CONFIG_URI:// 17 /* int */
+ return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
+ case capi.SQLITE_CONFIG_LOOKASIDE: // 13 /* int int */
+ return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
+ case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29 /* sqlite3_int64 */
+ return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
+ case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
+ case capi.SQLITE_CONFIG_GETMUTEX: // 11 /* sqlite3_mutex_methods* */
+ case capi.SQLITE_CONFIG_GETPCACHE2: // 19 /* sqlite3_pcache_methods2* */
+ case capi.SQLITE_CONFIG_GETPCACHE: // 15 /* no-op */
+ case capi.SQLITE_CONFIG_HEAP: // 8 /* void*, int nByte, int min */
+ case capi.SQLITE_CONFIG_LOG: // 16 /* xFunc, void* */
+ case capi.SQLITE_CONFIG_MALLOC:// 4 /* sqlite3_mem_methods* */
+ case capi.SQLITE_CONFIG_MMAP_SIZE: // 22 /* sqlite3_int64, sqlite3_int64 */
+ case capi.SQLITE_CONFIG_MULTITHREAD: // 2 /* nil */
+ case capi.SQLITE_CONFIG_MUTEX: // 10 /* sqlite3_mutex_methods* */
+ case capi.SQLITE_CONFIG_PAGECACHE: // 7 /* void*, int sz, int N */
+ case capi.SQLITE_CONFIG_PCACHE2: // 18 /* sqlite3_pcache_methods2* */
+ case capi.SQLITE_CONFIG_PCACHE: // 14 /* no-op */
+ case capi.SQLITE_CONFIG_PCACHE_HDRSZ: // 24 /* int *psz */
+ case capi.SQLITE_CONFIG_PMASZ: // 25 /* unsigned int szPma */
+ case capi.SQLITE_CONFIG_SERIALIZED: // 3 /* nil */
+ case capi.SQLITE_CONFIG_SINGLETHREAD: // 1 /* nil */:
+ case capi.SQLITE_CONFIG_SQLLOG: // 21 /* xSqllog, void* */
+ case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: // 23 /* int nByte */
+ default:
+ /* maintenance note: we specifically do not include
+ SQLITE_CONFIG_ROWID_IN_VIEW here, on the grounds that
+ it's only for legacy support and no apps written with
+ this API require that. */
+ return capi.SQLITE_NOTFOUND;
+ }
+ };
+ }/* sqlite3_config() */
+
+ {/*auto-extension bindings.*/
+ const __autoExtFptr = new Set;
+
+ capi.sqlite3_auto_extension = function(fPtr){
+ if( fPtr instanceof Function ){
+ fPtr = wasm.installFunction('i(ppp)', fPtr);
+ }else if( 1!==arguments.length || !wasm.isPtr(fPtr) ){
+ return capi.SQLITE_MISUSE;
+ }
+ const rc = wasm.exports.sqlite3_auto_extension(fPtr);
+ if( fPtr!==arguments[0] ){
+ if(0===rc) __autoExtFptr.add(fPtr);
+ else wasm.uninstallFunction(fPtr);
+ }
+ return rc;
+ };
+
+ capi.sqlite3_cancel_auto_extension = function(fPtr){
+ /* We do not do an automatic JS-to-WASM function conversion here
+ because it would be senseless: the converted pointer would
+ never possibly match an already-installed one. */;
+ if(!fPtr || 1!==arguments.length || !wasm.isPtr(fPtr)) return 0;
+ return wasm.exports.sqlite3_cancel_auto_extension(fPtr);
+ /* Note that it "cannot happen" that a client passes a pointer which
+ is in __autoExtFptr because __autoExtFptr only contains automatic
+ conversions created inside sqlite3_auto_extension() and
+ never exposed to the client. */
+ };
+
+ capi.sqlite3_reset_auto_extension = function(){
+ wasm.exports.sqlite3_reset_auto_extension();
+ for(const fp of __autoExtFptr) wasm.uninstallFunction(fp);
+ __autoExtFptr.clear();
+ };
+ }/* auto-extension */
+
+ const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
+ if( pKvvfs ){/* kvvfs-specific glue */
+ if(util.isUIThread()){
+ const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
+ wasm.exports.sqlite3__wasm_kvvfs_methods()
+ );
+ delete capi.sqlite3_kvvfs_methods;
+
+ const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
+ pstack = wasm.pstack;
+
+ const kvvfsStorage = (zClass)=>
+ ((115/*=='s'*/===wasm.peek(zClass))
+ ? sessionStorage : localStorage);
+
+ /**
+ Implementations for members of the object referred to by
+ sqlite3__wasm_kvvfs_methods(). We swap out the native
+ implementations with these, which use localStorage or
+ sessionStorage for their backing store.
+ */
+ const kvvfsImpls = {
+ xRead: (zClass, zKey, zBuf, nBuf)=>{
+ const stack = pstack.pointer,
+ astack = wasm.scopedAllocPush();
+ try {
+ const zXKey = kvvfsMakeKey(zClass,zKey);
+ if(!zXKey) return -3/*OOM*/;
+ const jKey = wasm.cstrToJs(zXKey);
+ const jV = kvvfsStorage(zClass).getItem(jKey);
+ if(!jV) return -1;
+ const nV = jV.length /* Note that we are relying 100% on v being
+ ASCII so that jV.length is equal to the
+ C-string's byte length. */;
+ if(nBuf<=0) return nV;
+ else if(1===nBuf){
+ wasm.poke(zBuf, 0);
+ return nV;
+ }
+ const zV = wasm.scopedAllocCString(jV);
+ if(nBuf > nV + 1) nBuf = nV + 1;
+ wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1);
+ wasm.poke(zBuf + nBuf - 1, 0);
+ return nBuf - 1;
+ }catch(e){
+ console.error("kvstorageRead()",e);
+ return -2;
+ }finally{
+ pstack.restore(stack);
+ wasm.scopedAllocPop(astack);
+ }
+ },
+ xWrite: (zClass, zKey, zData)=>{
+ const stack = pstack.pointer;
+ try {
+ const zXKey = kvvfsMakeKey(zClass,zKey);
+ if(!zXKey) return 1/*OOM*/;
+ const jKey = wasm.cstrToJs(zXKey);
+ kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
+ return 0;
+ }catch(e){
+ console.error("kvstorageWrite()",e);
+ return capi.SQLITE_IOERR;
+ }finally{
+ pstack.restore(stack);
+ }
+ },
+ xDelete: (zClass, zKey)=>{
+ const stack = pstack.pointer;
+ try {
+ const zXKey = kvvfsMakeKey(zClass,zKey);
+ if(!zXKey) return 1/*OOM*/;
+ kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey));
+ return 0;
+ }catch(e){
+ console.error("kvstorageDelete()",e);
+ return capi.SQLITE_IOERR;
+ }finally{
+ pstack.restore(stack);
+ }
+ }
+ }/*kvvfsImpls*/;
+ for(const k of Object.keys(kvvfsImpls)){
+ kvvfsMethods[kvvfsMethods.memberKey(k)] =
+ wasm.installFunction(
+ kvvfsMethods.memberSignature(k),
+ kvvfsImpls[k]
+ );
+ }
+ }else{
+ /* Worker thread: unregister kvvfs to avoid it being used
+ for anything other than local/sessionStorage. It "can"
+ be used that way but it's not really intended to be. */
+ capi.sqlite3_vfs_unregister(pKvvfs);
+ }
+ }/*pKvvfs*/
+
+ /* Warn if client-level code makes use of FuncPtrAdapter. */
+ wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
+
+ const StructBinder = sqlite3.StructBinder
+ /* we require a local alias b/c StructBinder is removed from the sqlite3
+ object during the final steps of the API cleanup. */;
+ /**
+ Installs a StructBinder-bound function pointer member of the
+ given name and function in the given StructBinder.StructType
+ target object.
+
+ It creates a WASM proxy for the given function and arranges for
+ that proxy to be cleaned up when tgt.dispose() is called. Throws
+ on the slightest hint of error, e.g. tgt is-not-a StructType,
+ name does not map to a struct-bound member, etc.
+
+ As a special case, if the given function is a pointer, then
+ `wasm.functionEntry()` is used to validate that it is a known
+ function. If so, it is used as-is with no extra level of proxying
+ or cleanup, else an exception is thrown. It is legal to pass a
+ value of 0, indicating a NULL pointer, with the caveat that 0
+ _is_ a legal function pointer in WASM but it will not be accepted
+ as such _here_. (Justification: the function at address zero must
+ be one which initially came from the WASM module, not a method we
+ want to bind to a virtual table or VFS.)
+
+ This function returns a proxy for itself which is bound to tgt
+ and takes 2 args (name,func). That function returns the same
+ thing as this one, permitting calls to be chained.
+
+ If called with only 1 arg, it has no side effects but returns a
+ func with the same signature as described above.
+
+ ACHTUNG: because we cannot generically know how to transform JS
+ exceptions into result codes, the installed functions do no
+ automatic catching of exceptions. It is critical, to avoid
+ undefined behavior in the C layer, that methods mapped via
+ this function do not throw. The exception, as it were, to that
+ rule is...
+
+ If applyArgcCheck is true then each JS function (as opposed to
+ function pointers) gets wrapped in a proxy which asserts that it
+ is passed the expected number of arguments, throwing if the
+ argument count does not match expectations. That is only intended
+ for dev-time usage for sanity checking, and may leave the C
+ environment in an undefined state.
+ */
+ const installMethod = function callee(
+ tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
+ ){
+ if(!(tgt instanceof StructBinder.StructType)){
+ toss("Usage error: target object is-not-a StructType.");
+ }else if(!(func instanceof Function) && !wasm.isPtr(func)){
+ toss("Usage errror: expecting a Function or WASM pointer to one.");
+ }
+ if(1===arguments.length){
+ return (n,f)=>callee(tgt, n, f, applyArgcCheck);
+ }
+ if(!callee.argcProxy){
+ callee.argcProxy = function(tgt, funcName, func,sig){
+ return function(...args){
+ if(func.length!==arguments.length){
+ toss("Argument mismatch for",
+ tgt.structInfo.name+"::"+funcName
+ +": Native signature is:",sig);
+ }
+ return func.apply(this, args);
+ }
+ };
+ /* An ondispose() callback for use with
+ StructBinder-created types. */
+ callee.removeFuncList = function(){
+ if(this.ondispose.__removeFuncList){
+ this.ondispose.__removeFuncList.forEach(
+ (v,ndx)=>{
+ if('number'===typeof v){
+ try{wasm.uninstallFunction(v)}
+ catch(e){/*ignore*/}
+ }
+ /* else it's a descriptive label for the next number in
+ the list. */
+ }
+ );
+ delete this.ondispose.__removeFuncList;
+ }
+ };
+ }/*static init*/
+ const sigN = tgt.memberSignature(name);
+ if(sigN.length<2){
+ toss("Member",name,"does not have a function pointer signature:",sigN);
+ }
+ const memKey = tgt.memberKey(name);
+ const fProxy = (applyArgcCheck && !wasm.isPtr(func))
+ /** This middle-man proxy is only for use during development, to
+ confirm that we always pass the proper number of
+ arguments. We know that the C-level code will always use the
+ correct argument count. */
+ ? callee.argcProxy(tgt, memKey, func, sigN)
+ : func;
+ if(wasm.isPtr(fProxy)){
+ if(fProxy && !wasm.functionEntry(fProxy)){
+ toss("Pointer",fProxy,"is not a WASM function table entry.");
+ }
+ tgt[memKey] = fProxy;
+ }else{
+ const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
+ tgt[memKey] = pFunc;
+ if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
+ tgt.addOnDispose('ondispose.__removeFuncList handler',
+ callee.removeFuncList);
+ tgt.ondispose.__removeFuncList = [];
+ }
+ tgt.ondispose.__removeFuncList.push(memKey, pFunc);
+ }
+ return (n,f)=>callee(tgt, n, f, applyArgcCheck);
+ }/*installMethod*/;
+ installMethod.installMethodArgcCheck = false;
+
+ /**
+ Installs methods into the given StructBinder.StructType-type
+ instance. Each entry in the given methods object must map to a
+ known member of the given StructType, else an exception will be
+ triggered. See installMethod() for more details, including the
+ semantics of the 3rd argument.
+
+ As an exception to the above, if any two or more methods in the
+ 2nd argument are the exact same function, installMethod() is
+ _not_ called for the 2nd and subsequent instances, and instead
+ those instances get assigned the same method pointer which is
+ created for the first instance. This optimization is primarily to
+ accommodate special handling of sqlite3_module::xConnect and
+ xCreate methods.
+
+ On success, returns its first argument. Throws on error.
+ */
+ const installMethods = function(
+ structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
+ ){
+ const seen = new Map /* map of <Function, memberName> */;
+ for(const k of Object.keys(methods)){
+ const m = methods[k];
+ const prior = seen.get(m);
+ if(prior){
+ const mkey = structInstance.memberKey(k);
+ structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
+ }else{
+ installMethod(structInstance, k, m, applyArgcCheck);
+ seen.set(m, k);
+ }
+ }
+ return structInstance;
+ };
+
+ /**
+ Equivalent to calling installMethod(this,...arguments) with a
+ first argument of this object. If called with 1 or 2 arguments
+ and the first is an object, it's instead equivalent to calling
+ installMethods(this,...arguments).
+ */
+ StructBinder.StructType.prototype.installMethod = function callee(
+ name, func, applyArgcCheck = installMethod.installMethodArgcCheck
+ ){
+ return (arguments.length < 3 && name && 'object'===typeof name)
+ ? installMethods(this, ...arguments)
+ : installMethod(this, ...arguments);
+ };
+
+ /**
+ Equivalent to calling installMethods() with a first argument
+ of this object.
+ */
+ StructBinder.StructType.prototype.installMethods = function(
+ methods, applyArgcCheck = installMethod.installMethodArgcCheck
+ ){
+ return installMethods(this, methods, applyArgcCheck);
+ };
+
+});
+/* END FILE: api/sqlite3-api-glue.c-pp.js */
+/* BEGIN FILE: ./bld/sqlite3-api-build-version.js */
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ sqlite3.version = {"libVersion": "3.47.1", "libVersionNumber": 3047001, "sourceId": "2024-11-25 12:07:48 b95d11e958643b969c47a8e5857f3793b9e69700b8f1469371386369a26e577e","downloadVersion": 3470100};
+});
+/* END FILE: ./bld/sqlite3-api-build-version.js */
+/* BEGIN FILE: api/sqlite3-api-oo1.c-pp.js */
+/*
+ 2022-07-22
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file contains the so-called OO #1 API wrapper for the sqlite3
+ WASM build. It requires that sqlite3-api-glue.js has already run
+ and it installs its deliverable as globalThis.sqlite3.oo1.
+*/
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ const toss = (...args)=>{throw new Error(args.join(' '))};
+ const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
+
+ const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
+ /* What follows is colloquially known as "OO API #1". It is a
+ binding of the sqlite3 API which is designed to be run within
+ the same thread (main or worker) as the one in which the
+ sqlite3 WASM binding was initialized. This wrapper cannot use
+ the sqlite3 binding if, e.g., the wrapper is in the main thread
+ and the sqlite3 API is in a worker. */
+
+ /**
+ In order to keep clients from manipulating, perhaps
+ inadvertently, the underlying pointer values of DB and Stmt
+ instances, we'll gate access to them via the `pointer` property
+ accessor and store their real values in this map. Keys = DB/Stmt
+ objects, values = pointer values. This also unifies how those are
+ accessed, for potential use downstream via custom
+ wasm.xWrap() function signatures which know how to extract
+ it.
+ */
+ const __ptrMap = new WeakMap();
+ /**
+ Map of DB instances to objects, each object being a map of Stmt
+ wasm pointers to Stmt objects.
+ */
+ const __stmtMap = new WeakMap();
+
+ /** If object opts has _its own_ property named p then that
+ property's value is returned, else dflt is returned. */
+ const getOwnOption = (opts, p, dflt)=>{
+ const d = Object.getOwnPropertyDescriptor(opts,p);
+ return d ? d.value : dflt;
+ };
+
+ // Documented in DB.checkRc()
+ const checkSqlite3Rc = function(dbPtr, sqliteResultCode){
+ if(sqliteResultCode){
+ if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
+ toss3(
+ sqliteResultCode,
+ "sqlite3 result code",sqliteResultCode+":",
+ (dbPtr
+ ? capi.sqlite3_errmsg(dbPtr)
+ : capi.sqlite3_errstr(sqliteResultCode))
+ );
+ }
+ return arguments[0];
+ };
+
+ /**
+ sqlite3_trace_v2() callback which gets installed by the DB ctor
+ if its open-flags contain "t".
+ */
+ const __dbTraceToConsole =
+ wasm.installFunction('i(ippp)', function(t,c,p,x){
+ if(capi.SQLITE_TRACE_STMT===t){
+ // x == SQL, p == sqlite3_stmt*
+ console.log("SQL TRACE #"+(++this.counter)+' via sqlite3@'+c+':',
+ wasm.cstrToJs(x));
+ }
+ }.bind({counter: 0}));
+
+ /**
+ A map of sqlite3_vfs pointers to SQL code or a callback function
+ to run when the DB constructor opens a database with the given
+ VFS. In the latter case, the call signature is
+ (theDbObject,sqlite3Namespace) and the callback is expected to
+ throw on error.
+ */
+ const __vfsPostOpenCallback = Object.create(null);
+
+
+ /**
+ A proxy for DB class constructors. It must be called with the
+ being-construct DB object as its "this". See the DB constructor
+ for the argument docs. This is split into a separate function
+ in order to enable simple creation of special-case DB constructors,
+ e.g. JsStorageDb and OpfsDb.
+
+ Expects to be passed a configuration object with the following
+ properties:
+
+ - `.filename`: the db filename. It may be a special name like ":memory:"
+ or "".
+
+ - `.flags`: as documented in the DB constructor.
+
+ - `.vfs`: as documented in the DB constructor.
+
+ It also accepts those as the first 3 arguments.
+ */
+ const dbCtorHelper = function ctor(...args){
+ if(!ctor._name2vfs){
+ /**
+ Map special filenames which we handle here (instead of in C)
+ to some helpful metadata...
+
+ As of 2022-09-20, the C API supports the names :localStorage:
+ and :sessionStorage: for kvvfs. However, C code cannot
+ determine (without embedded JS code, e.g. via Emscripten's
+ EM_JS()) whether the kvvfs is legal in the current browser
+ context (namely the main UI thread). In order to help client
+ code fail early on, instead of it being delayed until they
+ try to read or write a kvvfs-backed db, we'll check for those
+ names here and throw if they're not legal in the current
+ context.
+ */
+ ctor._name2vfs = Object.create(null);
+ const isWorkerThread = ('function'===typeof importScripts/*===running in worker thread*/)
+ ? (n)=>toss3("The VFS for",n,"is only available in the main window thread.")
+ : false;
+ ctor._name2vfs[':localStorage:'] = {
+ vfs: 'kvvfs', filename: isWorkerThread || (()=>'local')
+ };
+ ctor._name2vfs[':sessionStorage:'] = {
+ vfs: 'kvvfs', filename: isWorkerThread || (()=>'session')
+ };
+ }
+ const opt = ctor.normalizeArgs(...args);
+ let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
+ if(('string'!==typeof fn && 'number'!==typeof fn)
+ || 'string'!==typeof flagsStr
+ || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
+ sqlite3.config.error("Invalid DB ctor args",opt,arguments);
+ toss3("Invalid arguments for DB constructor.");
+ }
+ let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
+ const vfsCheck = ctor._name2vfs[fnJs];
+ if(vfsCheck){
+ vfsName = vfsCheck.vfs;
+ fn = fnJs = vfsCheck.filename(fnJs);
+ }
+ let pDb, oflags = 0;
+ if( flagsStr.indexOf('c')>=0 ){
+ oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
+ }
+ if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
+ if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
+ oflags |= capi.SQLITE_OPEN_EXRESCODE;
+ const stack = wasm.pstack.pointer;
+ try {
+ const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
+ let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
+ pDb = wasm.peekPtr(pPtr);
+ checkSqlite3Rc(pDb, rc);
+ capi.sqlite3_extended_result_codes(pDb, 1);
+ if(flagsStr.indexOf('t')>=0){
+ capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
+ __dbTraceToConsole, pDb);
+ }
+ }catch( e ){
+ if( pDb ) capi.sqlite3_close_v2(pDb);
+ throw e;
+ }finally{
+ wasm.pstack.restore(stack);
+ }
+ this.filename = fnJs;
+ __ptrMap.set(this, pDb);
+ __stmtMap.set(this, Object.create(null));
+ try{
+ // Check for per-VFS post-open SQL/callback...
+ const pVfs = capi.sqlite3_js_db_vfs(pDb)
+ || toss3("Internal error: cannot get VFS for new db handle.");
+ const postInitSql = __vfsPostOpenCallback[pVfs];
+ if(postInitSql){
+ /**
+ Reminder: if this db is encrypted and the client did _not_ pass
+ in the key, any init code will fail, causing the ctor to throw.
+ We don't actually know whether the db is encrypted, so we cannot
+ sensibly apply any heuristics which skip the init code only for
+ encrypted databases for which no key has yet been supplied.
+ */
+ if(postInitSql instanceof Function){
+ postInitSql(this, sqlite3);
+ }else{
+ checkSqlite3Rc(
+ pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
+ );
+ }
+ }
+ }catch(e){
+ this.close();
+ throw e;
+ }
+ };
+
+ /**
+ Sets a callback which should be called after a db is opened with
+ the given sqlite3_vfs pointer. The 2nd argument must be a
+ function, which gets called with
+ (theOo1DbObject,sqlite3Namespace) at the end of the DB()
+ constructor. The function must throw on error, in which case the
+ db is closed and the exception is propagated. This function is
+ intended only for use by DB subclasses or sqlite3_vfs
+ implementations.
+
+ Prior to 2024-07-22, it was legal to pass SQL code as the second
+ argument, but that can interfere with a client's ability to run
+ pragmas which must be run before anything else, namely (pragma
+ locking_mode=exclusive) for use with WAL mode. That capability
+ had only ever been used as an internal detail of the two OPFS
+ VFSes, and they no longer use it that way.
+ */
+ dbCtorHelper.setVfsPostOpenCallback = function(pVfs, callback){
+ if( !(callback instanceof Function)){
+ toss3("dbCtorHelper.setVfsPostOpenCallback() should not be used with "+
+ "a non-function argument.",arguments);
+ }
+ __vfsPostOpenCallback[pVfs] = callback;
+ };
+
+ /**
+ A helper for DB constructors. It accepts either a single
+ config-style object or up to 3 arguments (filename, dbOpenFlags,
+ dbVfsName). It returns a new object containing:
+
+ { filename: ..., flags: ..., vfs: ... }
+
+ If passed an object, any additional properties it has are copied
+ as-is into the new object.
+ */
+ dbCtorHelper.normalizeArgs = function(filename=':memory:',flags = 'c',vfs = null){
+ const arg = {};
+ if(1===arguments.length && arguments[0] && 'object'===typeof arguments[0]){
+ Object.assign(arg, arguments[0]);
+ if(undefined===arg.flags) arg.flags = 'c';
+ if(undefined===arg.vfs) arg.vfs = null;
+ if(undefined===arg.filename) arg.filename = ':memory:';
+ }else{
+ arg.filename = filename;
+ arg.flags = flags;
+ arg.vfs = vfs;
+ }
+ return arg;
+ };
+ /**
+ The DB class provides a high-level OO wrapper around an sqlite3
+ db handle.
+
+ The given db filename must be resolvable using whatever
+ filesystem layer (virtual or otherwise) is set up for the default
+ sqlite3 VFS.
+
+ Note that the special sqlite3 db names ":memory:" and ""
+ (temporary db) have their normal special meanings here and need
+ not resolve to real filenames, but "" uses an on-storage
+ temporary database and requires that the VFS support that.
+
+ The second argument specifies the open/create mode for the
+ database. It must be string containing a sequence of letters (in
+ any order, but case sensitive) specifying the mode:
+
+ - "c": create if it does not exist, else fail if it does not
+ exist. Implies the "w" flag.
+
+ - "w": write. Implies "r": a db cannot be write-only.
+
+ - "r": read-only if neither "w" nor "c" are provided, else it
+ is ignored.
+
+ - "t": enable tracing of SQL executed on this database handle,
+ sending it to `console.log()`. To disable it later, call
+ `sqlite3.capi.sqlite3_trace_v2(thisDb.pointer, 0, 0, 0)`.
+
+ If "w" is not provided, the db is implicitly read-only, noting
+ that "rc" is meaningless
+
+ Any other letters are currently ignored. The default is
+ "c". These modes are ignored for the special ":memory:" and ""
+ names and _may_ be ignored altogether for certain VFSes.
+
+ The final argument is analogous to the final argument of
+ sqlite3_open_v2(): the name of an sqlite3 VFS. Pass a falsy value,
+ or none at all, to use the default. If passed a value, it must
+ be the string name of a VFS.
+
+ The constructor optionally (and preferably) takes its arguments
+ in the form of a single configuration object with the following
+ properties:
+
+ - `filename`: database file name
+ - `flags`: open-mode flags
+ - `vfs`: the VFS fname
+
+
+ The `filename` and `vfs` arguments may be either JS strings or
+ C-strings allocated via WASM. `flags` is required to be a JS
+ string (because it's specific to this API, which is specific
+ to JS).
+
+ For purposes of passing a DB instance to C-style sqlite3
+ functions, the DB object's read-only `pointer` property holds its
+ `sqlite3*` pointer value. That property can also be used to check
+ whether this DB instance is still open: it will evaluate to
+ `undefined` after the DB object's close() method is called.
+
+ In the main window thread, the filenames `":localStorage:"` and
+ `":sessionStorage:"` are special: they cause the db to use either
+ localStorage or sessionStorage for storing the database using
+ the kvvfs. If one of these names are used, they trump
+ any vfs name set in the arguments.
+ */
+ const DB = function(...args){
+ dbCtorHelper.apply(this, args);
+ };
+ DB.dbCtorHelper = dbCtorHelper;
+
+ /**
+ Internal-use enum for mapping JS types to DB-bindable types.
+ These do not (and need not) line up with the SQLITE_type
+ values. All values in this enum must be truthy and distinct
+ but they need not be numbers.
+ */
+ const BindTypes = {
+ null: 1,
+ number: 2,
+ string: 3,
+ boolean: 4,
+ blob: 5
+ };
+ BindTypes['undefined'] == BindTypes.null;
+ if(wasm.bigIntEnabled){
+ BindTypes.bigint = BindTypes.number;
+ }
+
+ /**
+ This class wraps sqlite3_stmt. Calling this constructor
+ directly will trigger an exception. Use DB.prepare() to create
+ new instances.
+
+ For purposes of passing a Stmt instance to C-style sqlite3
+ functions, its read-only `pointer` property holds its `sqlite3_stmt*`
+ pointer value.
+
+ Other non-function properties include:
+
+ - `db`: the DB object which created the statement.
+
+ - `columnCount`: the number of result columns in the query, or 0
+ for queries which cannot return results. This property is a proxy
+ for sqlite3_column_count() and its use in loops should be avoided
+ because of the call overhead associated with that. The
+ `columnCount` is not cached when the Stmt is created because a
+ schema change made via a separate db connection between this
+ statement's preparation and when it is stepped may invalidate it.
+
+ - `parameterCount`: the number of bindable parameters in the query.
+
+ As a general rule, most methods of this class will throw if
+ called on an instance which has been finalized. For brevity's
+ sake, the method docs do not all repeat this warning.
+ */
+ const Stmt = function(){
+ if(BindTypes!==arguments[2]){
+ toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
+ }
+ this.db = arguments[0];
+ __ptrMap.set(this, arguments[1]);
+ this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer);
+ };
+
+ /** Throws if the given DB has been closed, else it is returned. */
+ const affirmDbOpen = function(db){
+ if(!db.pointer) toss3("DB has been closed.");
+ return db;
+ };
+
+ /** Throws if ndx is not an integer or if it is out of range
+ for stmt.columnCount, else returns stmt.
+
+ Reminder: this will also fail after the statement is finalized
+ but the resulting error will be about an out-of-bounds column
+ index rather than a statement-is-finalized error.
+ */
+ const affirmColIndex = function(stmt,ndx){
+ if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){
+ toss3("Column index",ndx,"is out of range.");
+ }
+ return stmt;
+ };
+
+ /**
+ Expects to be passed the `arguments` object from DB.exec(). Does
+ the argument processing/validation, throws on error, and returns
+ a new object on success:
+
+ { sql: the SQL, opt: optionsObj, cbArg: function}
+
+ The opt object is a normalized copy of any passed to this
+ function. The sql will be converted to a string if it is provided
+ in one of the supported non-string formats.
+
+ cbArg is only set if the opt.callback or opt.resultRows are set,
+ in which case it's a function which expects to be passed the
+ current Stmt and returns the callback argument of the type
+ indicated by the input arguments.
+ */
+ const parseExecArgs = function(db, args){
+ const out = Object.create(null);
+ out.opt = Object.create(null);
+ switch(args.length){
+ case 1:
+ if('string'===typeof args[0] || util.isSQLableTypedArray(args[0])){
+ out.sql = args[0];
+ }else if(Array.isArray(args[0])){
+ out.sql = args[0];
+ }else if(args[0] && 'object'===typeof args[0]){
+ out.opt = args[0];
+ out.sql = out.opt.sql;
+ }
+ break;
+ case 2:
+ out.sql = args[0];
+ out.opt = args[1];
+ break;
+ default: toss3("Invalid argument count for exec().");
+ };
+ out.sql = util.flexibleString(out.sql);
+ if('string'!==typeof out.sql){
+ toss3("Missing SQL argument or unsupported SQL value type.");
+ }
+ const opt = out.opt;
+ switch(opt.returnValue){
+ case 'resultRows':
+ if(!opt.resultRows) opt.resultRows = [];
+ out.returnVal = ()=>opt.resultRows;
+ break;
+ case 'saveSql':
+ if(!opt.saveSql) opt.saveSql = [];
+ out.returnVal = ()=>opt.saveSql;
+ break;
+ case undefined:
+ case 'this':
+ out.returnVal = ()=>db;
+ break;
+ default:
+ toss3("Invalid returnValue value:",opt.returnValue);
+ }
+ if(!opt.callback && !opt.returnValue && undefined!==opt.rowMode){
+ if(!opt.resultRows) opt.resultRows = [];
+ out.returnVal = ()=>opt.resultRows;
+ }
+ if(opt.callback || opt.resultRows){
+ switch((undefined===opt.rowMode) ? 'array' : opt.rowMode) {
+ case 'object':
+ out.cbArg = (stmt,cache)=>{
+ if( !cache.columnNames ) cache.columnNames = stmt.getColumnNames([]);
+ /* https://sqlite.org/forum/forumpost/3632183d2470617d:
+ conversion of rows to objects (key/val pairs) is
+ somewhat expensive for large data sets because of the
+ native-to-JS conversion of the column names. If we
+ instead cache the names and build objects from that
+ list of strings, it can run twice as fast. The
+ difference is not noticeable for small data sets but
+ becomes human-perceivable when enough rows are
+ involved. */
+ const row = stmt.get([]);
+ const rv = Object.create(null);
+ for( const i in cache.columnNames ) rv[cache.columnNames[i]] = row[i];
+ return rv;
+ };
+ break;
+ case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
+ case 'stmt':
+ if(Array.isArray(opt.resultRows)){
+ toss3("exec(): invalid rowMode for a resultRows array: must",
+ "be one of 'array', 'object',",
+ "a result column number, or column name reference.");
+ }
+ out.cbArg = (stmt)=>stmt;
+ break;
+ default:
+ if(util.isInt32(opt.rowMode)){
+ out.cbArg = (stmt)=>stmt.get(opt.rowMode);
+ break;
+ }else if('string'===typeof opt.rowMode
+ && opt.rowMode.length>1
+ && '$'===opt.rowMode[0]){
+ /* "$X": fetch column named "X" (case-sensitive!). Prior
+ to 2022-12-14 ":X" and "@X" were also permitted, but
+ having so many options is unnecessary and likely to
+ cause confusion. */
+ const $colName = opt.rowMode.substr(1);
+ out.cbArg = (stmt)=>{
+ const rc = stmt.get(Object.create(null))[$colName];
+ return (undefined===rc)
+ ? toss3(capi.SQLITE_NOTFOUND,
+ "exec(): unknown result column:",$colName)
+ : rc;
+ };
+ break;
+ }
+ toss3("Invalid rowMode:",opt.rowMode);
+ }
+ }
+ return out;
+ };
+
+ /**
+ Internal impl of the DB.selectValue(), selectArray(), and
+ selectObject() methods.
+ */
+ const __selectFirstRow = (db, sql, bind, ...getArgs)=>{
+ const stmt = db.prepare(sql);
+ try {
+ const rc = stmt.bind(bind).step() ? stmt.get(...getArgs) : undefined;
+ stmt.reset(/*for INSERT...RETURNING locking case*/);
+ return rc;
+ }finally{
+ stmt.finalize();
+ }
+ };
+
+ /**
+ Internal impl of the DB.selectArrays() and selectObjects()
+ methods.
+ */
+ const __selectAll =
+ (db, sql, bind, rowMode)=>db.exec({
+ sql, bind, rowMode, returnValue: 'resultRows'
+ });
+
+ /**
+ Expects to be given a DB instance or an `sqlite3*` pointer (may
+ be null) and an sqlite3 API result code. If the result code is
+ not falsy, this function throws an SQLite3Error with an error
+ message from sqlite3_errmsg(), using db (or, if db is-a DB,
+ db.pointer) as the db handle, or sqlite3_errstr() if db is
+ falsy. Note that if it's passed a non-error code like SQLITE_ROW
+ or SQLITE_DONE, it will still throw but the error string might be
+ "Not an error." The various non-0 non-error codes need to be
+ checked for in client code where they are expected.
+
+ The thrown exception's `resultCode` property will be the value of
+ the second argument to this function.
+
+ If it does not throw, it returns its first argument.
+ */
+ DB.checkRc = (db,resultCode)=>checkSqlite3Rc(db,resultCode);
+
+ DB.prototype = {
+ /** Returns true if this db handle is open, else false. */
+ isOpen: function(){
+ return !!this.pointer;
+ },
+ /** Throws if this given DB has been closed, else returns `this`. */
+ affirmOpen: function(){
+ return affirmDbOpen(this);
+ },
+ /**
+ Finalizes all open statements and closes this database
+ connection. This is a no-op if the db has already been
+ closed. After calling close(), `this.pointer` will resolve to
+ `undefined`, so that can be used to check whether the db
+ instance is still opened.
+
+ If this.onclose.before is a function then it is called before
+ any close-related cleanup.
+
+ If this.onclose.after is a function then it is called after the
+ db is closed but before auxiliary state like this.filename is
+ cleared.
+
+ Both onclose handlers are passed this object, with the onclose
+ object as their "this," noting that the db will have been
+ closed when onclose.after is called. If this db is not opened
+ when close() is called, neither of the handlers are called. Any
+ exceptions the handlers throw are ignored because "destructors
+ must not throw."
+
+ Note that garbage collection of a db handle, if it happens at
+ all, will never trigger close(), so onclose handlers are not a
+ reliable way to implement close-time cleanup or maintenance of
+ a db.
+ */
+ close: function(){
+ if(this.pointer){
+ if(this.onclose && (this.onclose.before instanceof Function)){
+ try{this.onclose.before(this)}
+ catch(e){/*ignore*/}
+ }
+ const pDb = this.pointer;
+ Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
+ if(s && s.pointer){
+ try{s.finalize()}
+ catch(e){/*ignore*/}
+ }
+ });
+ __ptrMap.delete(this);
+ __stmtMap.delete(this);
+ capi.sqlite3_close_v2(pDb);
+ if(this.onclose && (this.onclose.after instanceof Function)){
+ try{this.onclose.after(this)}
+ catch(e){/*ignore*/}
+ }
+ delete this.filename;
+ }
+ },
+ /**
+ Returns the number of changes, as per sqlite3_changes()
+ (if the first argument is false) or sqlite3_total_changes()
+ (if it's true). If the 2nd argument is true, it uses
+ sqlite3_changes64() or sqlite3_total_changes64(), which
+ will trigger an exception if this build does not have
+ BigInt support enabled.
+ */
+ changes: function(total=false,sixtyFour=false){
+ const p = affirmDbOpen(this).pointer;
+ if(total){
+ return sixtyFour
+ ? capi.sqlite3_total_changes64(p)
+ : capi.sqlite3_total_changes(p);
+ }else{
+ return sixtyFour
+ ? capi.sqlite3_changes64(p)
+ : capi.sqlite3_changes(p);
+ }
+ },
+ /**
+ Similar to the this.filename but returns the
+ sqlite3_db_filename() value for the given database name,
+ defaulting to "main". The argument may be either a JS string
+ or a pointer to a WASM-allocated C-string.
+ */
+ dbFilename: function(dbName='main'){
+ return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
+ },
+ /**
+ Returns the name of the given 0-based db number, as documented
+ for sqlite3_db_name().
+ */
+ dbName: function(dbNumber=0){
+ return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber);
+ },
+ /**
+ Returns the name of the sqlite3_vfs used by the given database
+ of this connection (defaulting to 'main'). The argument may be
+ either a JS string or a WASM C-string. Returns undefined if the
+ given db name is invalid. Throws if this object has been
+ close()d.
+ */
+ dbVfsName: function(dbName=0){
+ let rc;
+ const pVfs = capi.sqlite3_js_db_vfs(
+ affirmDbOpen(this).pointer, dbName
+ );
+ if(pVfs){
+ const v = new capi.sqlite3_vfs(pVfs);
+ try{ rc = wasm.cstrToJs(v.$zName) }
+ finally { v.dispose() }
+ }
+ return rc;
+ },
+ /**
+ Compiles the given SQL and returns a prepared Stmt. This is
+ the only way to create new Stmt objects. Throws on error.
+
+ The given SQL must be a string, a Uint8Array holding SQL, a
+ WASM pointer to memory holding the NUL-terminated SQL string,
+ or an array of strings. In the latter case, the array is
+ concatenated together, with no separators, to form the SQL
+ string (arrays are often a convenient way to formulate long
+ statements). If the SQL contains no statements, an
+ SQLite3Error is thrown.
+
+ Design note: the C API permits empty SQL, reporting it as a 0
+ result code and a NULL stmt pointer. Supporting that case here
+ would cause extra work for all clients: any use of the Stmt API
+ on such a statement will necessarily throw, so clients would be
+ required to check `stmt.pointer` after calling `prepare()` in
+ order to determine whether the Stmt instance is empty or not.
+ Long-time practice (with other sqlite3 script bindings)
+ suggests that the empty-prepare case is sufficiently rare that
+ supporting it here would simply hurt overall usability.
+ */
+ prepare: function(sql){
+ affirmDbOpen(this);
+ const stack = wasm.pstack.pointer;
+ let ppStmt, pStmt;
+ try{
+ ppStmt = wasm.pstack.alloc(8)/* output (sqlite3_stmt**) arg */;
+ DB.checkRc(this, capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null));
+ pStmt = wasm.peekPtr(ppStmt);
+ }
+ finally {
+ wasm.pstack.restore(stack);
+ }
+ if(!pStmt) toss3("Cannot prepare empty SQL.");
+ const stmt = new Stmt(this, pStmt, BindTypes);
+ __stmtMap.get(this)[pStmt] = stmt;
+ return stmt;
+ },
+ /**
+ Executes one or more SQL statements in the form of a single
+ string. Its arguments must be either (sql,optionsObject) or
+ (optionsObject). In the latter case, optionsObject.sql must
+ contain the SQL to execute. By default it returns this object
+ but that can be changed via the `returnValue` option as
+ described below. Throws on error.
+
+ If no SQL is provided, or a non-string is provided, an
+ exception is triggered. Empty SQL, on the other hand, is
+ simply a no-op.
+
+ The optional options object may contain any of the following
+ properties:
+
+ - `sql` = the SQL to run (unless it's provided as the first
+ argument). This must be of type string, Uint8Array, or an array
+ of strings. In the latter case they're concatenated together
+ as-is, _with no separator_ between elements, before evaluation.
+ The array form is often simpler for long hand-written queries.
+
+ - `bind` = a single value valid as an argument for
+ Stmt.bind(). This is _only_ applied to the _first_ non-empty
+ statement in the SQL which has any bindable parameters. (Empty
+ statements are skipped entirely.)
+
+ - `saveSql` = an optional array. If set, the SQL of each
+ executed statement is appended to this array before the
+ statement is executed (but after it is prepared - we don't have
+ the string until after that). Empty SQL statements are elided
+ but can have odd effects in the output. e.g. SQL of: `"select
+ 1; -- empty\n; select 2"` will result in an array containing
+ `["select 1;", "--empty \n; select 2"]`. That's simply how
+ sqlite3 records the SQL for the 2nd statement.
+
+ ==================================================================
+ The following options apply _only_ to the _first_ statement
+ which has a non-zero result column count, regardless of whether
+ the statement actually produces any result rows.
+ ==================================================================
+
+ - `columnNames`: if this is an array, the column names of the
+ result set are stored in this array before the callback (if
+ any) is triggered (regardless of whether the query produces any
+ result rows). If no statement has result columns, this value is
+ unchanged. Achtung: an SQL result may have multiple columns
+ with identical names.
+
+ - `callback` = a function which gets called for each row of the
+ result set, but only if that statement has any result rows. The
+ callback's "this" is the options object, noting that this
+ function synthesizes one if the caller does not pass one to
+ exec(). The second argument passed to the callback is always
+ the current Stmt object, as it's needed if the caller wants to
+ fetch the column names or some such (noting that they could
+ also be fetched via `this.columnNames`, if the client provides
+ the `columnNames` option). If the callback returns a literal
+ `false` (as opposed to any other falsy value, e.g. an implicit
+ `undefined` return), any ongoing statement-`step()` iteration
+ stops without an error. The return value of the callback is
+ otherwise ignored.
+
+ ACHTUNG: The callback MUST NOT modify the Stmt object. Calling
+ any of the Stmt.get() variants, Stmt.getColumnName(), or
+ similar, is legal, but calling step() or finalize() is
+ not. Member methods which are illegal in this context will
+ trigger an exception, but clients must also refrain from using
+ any lower-level (C-style) APIs which might modify the
+ statement.
+
+ The first argument passed to the callback defaults to an array of
+ values from the current result row but may be changed with ...
+
+ - `rowMode` = specifies the type of he callback's first argument.
+ It may be any of...
+
+ A) A string describing what type of argument should be passed
+ as the first argument to the callback:
+
+ A.1) `'array'` (the default) causes the results of
+ `stmt.get([])` to be passed to the `callback` and/or appended
+ to `resultRows`.
+
+ A.2) `'object'` causes the results of
+ `stmt.get(Object.create(null))` to be passed to the
+ `callback` and/or appended to `resultRows`. Achtung: an SQL
+ result may have multiple columns with identical names. In
+ that case, the right-most column will be the one set in this
+ object!
+
+ A.3) `'stmt'` causes the current Stmt to be passed to the
+ callback, but this mode will trigger an exception if
+ `resultRows` is an array because appending the transient
+ statement to the array would be downright unhelpful.
+
+ B) An integer, indicating a zero-based column in the result
+ row. Only that one single value will be passed on.
+
+ C) A string with a minimum length of 2 and leading character of
+ '$' will fetch the row as an object, extract that one field,
+ and pass that field's value to the callback. Note that these
+ keys are case-sensitive so must match the case used in the
+ SQL. e.g. `"select a A from t"` with a `rowMode` of `'$A'`
+ would work but `'$a'` would not. A reference to a column not in
+ the result set will trigger an exception on the first row (as
+ the check is not performed until rows are fetched). Note also
+ that `$` is a legal identifier character in JS so need not be
+ quoted.
+
+ Any other `rowMode` value triggers an exception.
+
+ - `resultRows`: if this is an array, it functions similarly to
+ the `callback` option: each row of the result set (if any),
+ with the exception that the `rowMode` 'stmt' is not legal. It
+ is legal to use both `resultRows` and `callback`, but
+ `resultRows` is likely much simpler to use for small data sets
+ and can be used over a WebWorker-style message interface.
+ exec() throws if `resultRows` is set and `rowMode` is 'stmt'.
+
+ - `returnValue`: is a string specifying what this function
+ should return:
+
+ A) The default value is (usually) `"this"`, meaning that the
+ DB object itself should be returned. The exception is if
+ the caller passes neither of `callback` nor `returnValue`
+ but does pass an explicit `rowMode` then the default
+ `returnValue` is `"resultRows"`, described below.
+
+ B) `"resultRows"` means to return the value of the
+ `resultRows` option. If `resultRows` is not set, this
+ function behaves as if it were set to an empty array.
+
+ C) `"saveSql"` means to return the value of the
+ `saveSql` option. If `saveSql` is not set, this
+ function behaves as if it were set to an empty array.
+
+ Potential TODOs:
+
+ - `bind`: permit an array of arrays/objects to bind. The first
+ sub-array would act on the first statement which has bindable
+ parameters (as it does now). The 2nd would act on the next such
+ statement, etc.
+
+ - `callback` and `resultRows`: permit an array entries with
+ semantics similar to those described for `bind` above.
+
+ */
+ exec: function(/*(sql [,obj]) || (obj)*/){
+ affirmDbOpen(this);
+ const arg = parseExecArgs(this, arguments);
+ if(!arg.sql){
+ return toss3("exec() requires an SQL string.");
+ }
+ const opt = arg.opt;
+ const callback = opt.callback;
+ const resultRows =
+ Array.isArray(opt.resultRows) ? opt.resultRows : undefined;
+ let stmt;
+ let bind = opt.bind;
+ let evalFirstResult = !!(
+ arg.cbArg || opt.columnNames || resultRows
+ ) /* true to step through the first result-returning statement */;
+ const stack = wasm.scopedAllocPush();
+ const saveSql = Array.isArray(opt.saveSql) ? opt.saveSql : undefined;
+ try{
+ const isTA = util.isSQLableTypedArray(arg.sql)
+ /* Optimization: if the SQL is a TypedArray we can save some string
+ conversion costs. */;
+ /* Allocate the two output pointers (ppStmt, pzTail) and heap
+ space for the SQL (pSql). When prepare_v2() returns, pzTail
+ will point to somewhere in pSql. */
+ let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
+ const ppStmt = wasm.scopedAlloc(
+ /* output (sqlite3_stmt**) arg and pzTail */
+ (2 * wasm.ptrSizeof) + (sqlByteLen + 1/* SQL + NUL */)
+ );
+ const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */;
+ let pSql = pzTail + wasm.ptrSizeof;
+ const pSqlEnd = pSql + sqlByteLen;
+ if(isTA) wasm.heap8().set(arg.sql, pSql);
+ else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false);
+ wasm.poke(pSql + sqlByteLen, 0/*NUL terminator*/);
+ while(pSql && wasm.peek(pSql, 'i8')
+ /* Maintenance reminder:^^^ _must_ be 'i8' or else we
+ will very likely cause an endless loop. What that's
+ doing is checking for a terminating NUL byte. If we
+ use i32 or similar then we read 4 bytes, read stuff
+ around the NUL terminator, and get stuck in and
+ endless loop at the end of the SQL, endlessly
+ re-preparing an empty statement. */ ){
+ wasm.pokePtr([ppStmt, pzTail], 0);
+ DB.checkRc(this, capi.sqlite3_prepare_v3(
+ this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail
+ ));
+ const pStmt = wasm.peekPtr(ppStmt);
+ pSql = wasm.peekPtr(pzTail);
+ sqlByteLen = pSqlEnd - pSql;
+ if(!pStmt) continue;
+ if(saveSql) saveSql.push(capi.sqlite3_sql(pStmt).trim());
+ stmt = new Stmt(this, pStmt, BindTypes);
+ if(bind && stmt.parameterCount){
+ stmt.bind(bind);
+ bind = null;
+ }
+ if(evalFirstResult && stmt.columnCount){
+ /* Only forward SELECT-style results for the FIRST query
+ in the SQL which potentially has them. */
+ let gotColNames = Array.isArray(
+ opt.columnNames
+ /* As reported in
+ https://sqlite.org/forum/forumpost/7774b773937cbe0a
+ we need to delay fetching of the column names until
+ after the first step() (if we step() at all) because
+ a schema change between the prepare() and step(), via
+ another connection, may invalidate the column count
+ and names. */) ? 0 : 1;
+ evalFirstResult = false;
+ if(arg.cbArg || resultRows){
+ const cbArgCache = Object.create(null)
+ /* 2nd arg for arg.cbArg, used by (at least) row-to-object
+ converter */;
+ for(; stmt.step(); stmt._lockedByExec = false){
+ if(0===gotColNames++){
+ stmt.getColumnNames(cbArgCache.columnNames = (opt.columnNames || []));
+ }
+ stmt._lockedByExec = true;
+ const row = arg.cbArg(stmt,cbArgCache);
+ if(resultRows) resultRows.push(row);
+ if(callback && false === callback.call(opt, row, stmt)){
+ break;
+ }
+ }
+ stmt._lockedByExec = false;
+ }
+ if(0===gotColNames){
+ /* opt.columnNames was provided but we visited no result rows */
+ stmt.getColumnNames(opt.columnNames);
+ }
+ }else{
+ stmt.step();
+ }
+ stmt.reset(
+ /* In order to trigger an exception in the
+ INSERT...RETURNING locking scenario:
+ https://sqlite.org/forum/forumpost/36f7a2e7494897df
+ */).finalize();
+ stmt = null;
+ }/*prepare() loop*/
+ }/*catch(e){
+ sqlite3.config.warn("DB.exec() is propagating exception",opt,e);
+ throw e;
+ }*/finally{
+ wasm.scopedAllocPop(stack);
+ if(stmt){
+ delete stmt._lockedByExec;
+ stmt.finalize();
+ }
+ }
+ return arg.returnVal();
+ }/*exec()*/,
+
+ /**
+ Creates a new UDF (User-Defined Function) which is accessible
+ via SQL code. This function may be called in any of the
+ following forms:
+
+ - (name, function)
+ - (name, function, optionsObject)
+ - (name, optionsObject)
+ - (optionsObject)
+
+ In the final two cases, the function must be defined as the
+ `callback` property of the options object (optionally called
+ `xFunc` to align with the C API documentation). In the final
+ case, the function's name must be the 'name' property.
+
+ The first two call forms can only be used for creating scalar
+ functions. Creating an aggregate or window function requires
+ the options-object form (see below for details).
+
+ UDFs can be removed as documented for
+ sqlite3_create_function_v2() and
+ sqlite3_create_window_function(), but doing so will "leak" the
+ JS-created WASM binding of those functions (meaning that their
+ entries in the WASM indirect function table still
+ exist). Eliminating that potential leak is a pending TODO.
+
+ On success, returns this object. Throws on error.
+
+ When called from SQL arguments to the UDF, and its result,
+ will be converted between JS and SQL with as much fidelity as
+ is feasible, triggering an exception if a type conversion
+ cannot be determined. The docs for sqlite3_create_function_v2()
+ describe the conversions in more detail.
+
+ The values set in the options object differ for scalar and
+ aggregate functions:
+
+ - Scalar: set the `xFunc` function-type property to the UDF
+ function.
+
+ - Aggregate: set the `xStep` and `xFinal` function-type
+ properties to the "step" and "final" callbacks for the
+ aggregate. Do not set the `xFunc` property.
+
+ - Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse`
+ function-type properties. Do not set the `xFunc` property.
+
+ The options object may optionally have an `xDestroy`
+ function-type property, as per sqlite3_create_function_v2().
+ Its argument will be the WASM-pointer-type value of the `pApp`
+ property, and this function will throw if `pApp` is defined but
+ is not null, undefined, or a numeric (WASM pointer)
+ value. i.e. `pApp`, if set, must be value suitable for use as a
+ WASM pointer argument, noting that `null` or `undefined` will
+ translate to 0 for that purpose.
+
+ The options object may contain flags to modify how
+ the function is defined:
+
+ - `arity`: the number of arguments which SQL calls to this
+ function expect or require. The default value is `xFunc.length`
+ or `xStep.length` (i.e. the number of declared parameters it
+ has) **MINUS 1** (see below for why). As a special case, if the
+ `length` is 0, its arity is also 0 instead of -1. A negative
+ arity value means that the function is variadic and may accept
+ any number of arguments, up to sqlite3's compile-time
+ limits. sqlite3 will enforce the argument count if is zero or
+ greater. The callback always receives a pointer to an
+ `sqlite3_context` object as its first argument. Any arguments
+ after that are from SQL code. The leading context argument does
+ _not_ count towards the function's arity. See the docs for
+ sqlite3.capi.sqlite3_create_function_v2() for why that argument
+ is needed in the interface.
+
+ The following options-object properties correspond to flags
+ documented at:
+
+ https://sqlite.org/c3ref/create_function.html
+
+ - `deterministic` = sqlite3.capi.SQLITE_DETERMINISTIC
+ - `directOnly` = sqlite3.capi.SQLITE_DIRECTONLY
+ - `innocuous` = sqlite3.capi.SQLITE_INNOCUOUS
+
+ Sidebar: the ability to add new WASM-accessible functions to
+ the runtime requires that the WASM build is compiled with the
+ equivalent functionality as that provided by Emscripten's
+ `-sALLOW_TABLE_GROWTH` flag.
+ */
+ createFunction: function f(name, xFunc, opt){
+ const isFunc = (f)=>(f instanceof Function);
+ switch(arguments.length){
+ case 1: /* (optionsObject) */
+ opt = name;
+ name = opt.name;
+ xFunc = opt.xFunc || 0;
+ break;
+ case 2: /* (name, callback|optionsObject) */
+ if(!isFunc(xFunc)){
+ opt = xFunc;
+ xFunc = opt.xFunc || 0;
+ }
+ break;
+ case 3: /* name, xFunc, opt */
+ break;
+ default: break;
+ }
+ if(!opt) opt = {};
+ if('string' !== typeof name){
+ toss3("Invalid arguments: missing function name.");
+ }
+ let xStep = opt.xStep || 0;
+ let xFinal = opt.xFinal || 0;
+ const xValue = opt.xValue || 0;
+ const xInverse = opt.xInverse || 0;
+ let isWindow = undefined;
+ if(isFunc(xFunc)){
+ isWindow = false;
+ if(isFunc(xStep) || isFunc(xFinal)){
+ toss3("Ambiguous arguments: scalar or aggregate?");
+ }
+ xStep = xFinal = null;
+ }else if(isFunc(xStep)){
+ if(!isFunc(xFinal)){
+ toss3("Missing xFinal() callback for aggregate or window UDF.");
+ }
+ xFunc = null;
+ }else if(isFunc(xFinal)){
+ toss3("Missing xStep() callback for aggregate or window UDF.");
+ }else{
+ toss3("Missing function-type properties.");
+ }
+ if(false === isWindow){
+ if(isFunc(xValue) || isFunc(xInverse)){
+ toss3("xValue and xInverse are not permitted for non-window UDFs.");
+ }
+ }else if(isFunc(xValue)){
+ if(!isFunc(xInverse)){
+ toss3("xInverse must be provided if xValue is.");
+ }
+ isWindow = true;
+ }else if(isFunc(xInverse)){
+ toss3("xValue must be provided if xInverse is.");
+ }
+ const pApp = opt.pApp;
+ if(undefined!==pApp &&
+ null!==pApp &&
+ (('number'!==typeof pApp) || !util.isInt32(pApp))){
+ toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
+ }
+ const xDestroy = opt.xDestroy || 0;
+ if(xDestroy && !isFunc(xDestroy)){
+ toss3("xDestroy property must be a function.");
+ }
+ let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
+ if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
+ if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
+ if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS;
+ name = name.toLowerCase();
+ const xArity = xFunc || xStep;
+ const arity = getOwnOption(opt, 'arity');
+ const arityArg = ('number'===typeof arity
+ ? arity
+ : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0));
+ let rc;
+ if( isWindow ){
+ rc = capi.sqlite3_create_window_function(
+ this.pointer, name, arityArg,
+ capi.SQLITE_UTF8 | fFlags, pApp || 0,
+ xStep, xFinal, xValue, xInverse, xDestroy);
+ }else{
+ rc = capi.sqlite3_create_function_v2(
+ this.pointer, name, arityArg,
+ capi.SQLITE_UTF8 | fFlags, pApp || 0,
+ xFunc, xStep, xFinal, xDestroy);
+ }
+ DB.checkRc(this, rc);
+ return this;
+ }/*createFunction()*/,
+ /**
+ Prepares the given SQL, step()s it one time, and returns
+ the value of the first result column. If it has no results,
+ undefined is returned.
+
+ If passed a second argument, it is treated like an argument
+ to Stmt.bind(), so may be any type supported by that
+ function. Passing the undefined value is the same as passing
+ no value, which is useful when...
+
+ If passed a 3rd argument, it is expected to be one of the
+ SQLITE_{typename} constants. Passing the undefined value is
+ the same as not passing a value.
+
+ Throws on error (e.g. malformed SQL).
+ */
+ selectValue: function(sql,bind,asType){
+ return __selectFirstRow(this, sql, bind, 0, asType);
+ },
+
+ /**
+ Runs the given query and returns an array of the values from
+ the first result column of each row of the result set. The 2nd
+ argument is an optional value for use in a single-argument call
+ to Stmt.bind(). The 3rd argument may be any value suitable for
+ use as the 2nd argument to Stmt.get(). If a 3rd argument is
+ desired but no bind data are needed, pass `undefined` for the 2nd
+ argument.
+
+ If there are no result rows, an empty array is returned.
+ */
+ selectValues: function(sql,bind,asType){
+ const stmt = this.prepare(sql), rc = [];
+ try {
+ stmt.bind(bind);
+ while(stmt.step()) rc.push(stmt.get(0,asType));
+ stmt.reset(/*for INSERT...RETURNING locking case*/);
+ }finally{
+ stmt.finalize();
+ }
+ return rc;
+ },
+
+ /**
+ Prepares the given SQL, step()s it one time, and returns an
+ array containing the values of the first result row. If it has
+ no results, `undefined` is returned.
+
+ If passed a second argument other than `undefined`, it is
+ treated like an argument to Stmt.bind(), so may be any type
+ supported by that function.
+
+ Throws on error (e.g. malformed SQL).
+ */
+ selectArray: function(sql,bind){
+ return __selectFirstRow(this, sql, bind, []);
+ },
+
+ /**
+ Prepares the given SQL, step()s it one time, and returns an
+ object containing the key/value pairs of the first result
+ row. If it has no results, `undefined` is returned.
+
+ Note that the order of returned object's keys is not guaranteed
+ to be the same as the order of the fields in the query string.
+
+ If passed a second argument other than `undefined`, it is
+ treated like an argument to Stmt.bind(), so may be any type
+ supported by that function.
+
+ Throws on error (e.g. malformed SQL).
+ */
+ selectObject: function(sql,bind){
+ return __selectFirstRow(this, sql, bind, {});
+ },
+
+ /**
+ Runs the given SQL and returns an array of all results, with
+ each row represented as an array, as per the 'array' `rowMode`
+ option to `exec()`. An empty result set resolves
+ to an empty array. The second argument, if any, is treated as
+ the 'bind' option to a call to exec().
+ */
+ selectArrays: function(sql,bind){
+ return __selectAll(this, sql, bind, 'array');
+ },
+
+ /**
+ Works identically to selectArrays() except that each value
+ in the returned array is an object, as per the 'object' `rowMode`
+ option to `exec()`.
+ */
+ selectObjects: function(sql,bind){
+ return __selectAll(this, sql, bind, 'object');
+ },
+
+ /**
+ Returns the number of currently-opened Stmt handles for this db
+ handle, or 0 if this DB instance is closed. Note that only
+ handles prepared via this.prepare() are counted, and not
+ handles prepared using capi.sqlite3_prepare_v3() (or
+ equivalent).
+ */
+ openStatementCount: function(){
+ return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
+ },
+
+ /**
+ Starts a transaction, calls the given callback, and then either
+ rolls back or commits the savepoint, depending on whether the
+ callback throws. The callback is passed this db object as its
+ only argument. On success, returns the result of the
+ callback. Throws on error.
+
+ Note that transactions may not be nested, so this will throw if
+ it is called recursively. For nested transactions, use the
+ savepoint() method or manually manage SAVEPOINTs using exec().
+
+ If called with 2 arguments, the first must be a keyword which
+ is legal immediately after a BEGIN statement, e.g. one of
+ "DEFERRED", "IMMEDIATE", or "EXCLUSIVE". Though the exact list
+ of supported keywords is not hard-coded here, in order to be
+ future-compatible, if the argument does not look like a single
+ keyword then an exception is triggered with a description of
+ the problem.
+ */
+ transaction: function(/* [beginQualifier,] */callback){
+ let opener = 'BEGIN';
+ if(arguments.length>1){
+ if(/[^a-zA-Z]/.test(arguments[0])){
+ toss3(capi.SQLITE_MISUSE, "Invalid argument for BEGIN qualifier.");
+ }
+ opener += ' '+arguments[0];
+ callback = arguments[1];
+ }
+ affirmDbOpen(this).exec(opener);
+ try {
+ const rc = callback(this);
+ this.exec("COMMIT");
+ return rc;
+ }catch(e){
+ this.exec("ROLLBACK");
+ throw e;
+ }
+ },
+
+ /**
+ This works similarly to transaction() but uses sqlite3's SAVEPOINT
+ feature. This function starts a savepoint (with an unspecified name)
+ and calls the given callback function, passing it this db object.
+ If the callback returns, the savepoint is released (committed). If
+ the callback throws, the savepoint is rolled back. If it does not
+ throw, it returns the result of the callback.
+ */
+ savepoint: function(callback){
+ affirmDbOpen(this).exec("SAVEPOINT oo1");
+ try {
+ const rc = callback(this);
+ this.exec("RELEASE oo1");
+ return rc;
+ }catch(e){
+ this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1");
+ throw e;
+ }
+ },
+
+ /**
+ A convenience form of DB.checkRc(this,resultCode). If it does
+ not throw, it returns this object.
+ */
+ checkRc: function(resultCode){
+ return checkSqlite3Rc(this, resultCode);
+ }
+ }/*DB.prototype*/;
+
+
+ /** Throws if the given Stmt has been finalized, else stmt is
+ returned. */
+ const affirmStmtOpen = function(stmt){
+ if(!stmt.pointer) toss3("Stmt has been closed.");
+ return stmt;
+ };
+
+ /** Returns an opaque truthy value from the BindTypes
+ enum if v's type is a valid bindable type, else
+ returns a falsy value. As a special case, a value of
+ undefined is treated as a bind type of null. */
+ const isSupportedBindType = function(v){
+ let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
+ switch(t){
+ case BindTypes.boolean:
+ case BindTypes.null:
+ case BindTypes.number:
+ case BindTypes.string:
+ return t;
+ case BindTypes.bigint:
+ if(wasm.bigIntEnabled) return t;
+ /* else fall through */
+ default:
+ return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
+ }
+ };
+
+ /**
+ If isSupportedBindType(v) returns a truthy value, this
+ function returns that value, else it throws.
+ */
+ const affirmSupportedBindType = function(v){
+ //sqlite3.config.log('affirmSupportedBindType',v);
+ return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v);
+ };
+
+ /**
+ If key is a number and within range of stmt's bound parameter
+ count, key is returned.
+
+ If key is not a number then it is checked against named
+ parameters. If a match is found, its index is returned.
+
+ Else it throws.
+ */
+ const affirmParamIndex = function(stmt,key){
+ const n = ('number'===typeof key)
+ ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
+ if(0===n || !util.isInt32(n)){
+ toss3("Invalid bind() parameter name: "+key);
+ }
+ else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range.");
+ return n;
+ };
+
+ /**
+ If stmt._lockedByExec is truthy, this throws an exception
+ complaining that the 2nd argument (an operation name,
+ e.g. "bind()") is not legal while the statement is "locked".
+ Locking happens before an exec()-like callback is passed a
+ statement, to ensure that the callback does not mutate or
+ finalize the statement. If it does not throw, it returns stmt.
+ */
+ const affirmNotLockedByExec = function(stmt,currentOpName){
+ if(stmt._lockedByExec){
+ toss3("Operation is illegal when statement is locked:",currentOpName);
+ }
+ return stmt;
+ };
+
+ /**
+ Binds a single bound parameter value on the given stmt at the
+ given index (numeric or named) using the given bindType (see
+ the BindTypes enum) and value. Throws on error. Returns stmt on
+ success.
+ */
+ const bindOne = function f(stmt,ndx,bindType,val){
+ affirmNotLockedByExec(affirmStmtOpen(stmt), 'bind()');
+ if(!f._){
+ f._tooBigInt = (v)=>toss3(
+ "BigInt value is too big to store without precision loss:", v
+ );
+ f._ = {
+ string: function(stmt, ndx, val, asBlob){
+ const [pStr, n] = wasm.allocCString(val, true);
+ const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
+ return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_WASM_DEALLOC);
+ }
+ };
+ }/* static init */
+ affirmSupportedBindType(val);
+ ndx = affirmParamIndex(stmt,ndx);
+ let rc = 0;
+ switch((null===val || undefined===val) ? BindTypes.null : bindType){
+ case BindTypes.null:
+ rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
+ break;
+ case BindTypes.string:
+ rc = f._.string(stmt, ndx, val, false);
+ break;
+ case BindTypes.number: {
+ let m;
+ if(util.isInt32(val)) m = capi.sqlite3_bind_int;
+ else if('bigint'===typeof val){
+ if(!util.bigIntFits64(val)){
+ f._tooBigInt(val);
+ }else if(wasm.bigIntEnabled){
+ m = capi.sqlite3_bind_int64;
+ }else if(util.bigIntFitsDouble(val)){
+ val = Number(val);
+ m = capi.sqlite3_bind_double;
+ }else{
+ f._tooBigInt(val);
+ }
+ }else{ // !int32, !bigint
+ val = Number(val);
+ if(wasm.bigIntEnabled && Number.isInteger(val)){
+ m = capi.sqlite3_bind_int64;
+ }else{
+ m = capi.sqlite3_bind_double;
+ }
+ }
+ rc = m(stmt.pointer, ndx, val);
+ break;
+ }
+ case BindTypes.boolean:
+ rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
+ break;
+ case BindTypes.blob: {
+ if('string'===typeof val){
+ rc = f._.string(stmt, ndx, val, true);
+ break;
+ }else if(val instanceof ArrayBuffer){
+ val = new Uint8Array(val);
+ }else if(!util.isBindableTypedArray(val)){
+ toss3("Binding a value as a blob requires",
+ "that it be a string, Uint8Array, Int8Array, or ArrayBuffer.");
+ }
+ const pBlob = wasm.alloc(val.byteLength || 1);
+ wasm.heap8().set(val.byteLength ? val : [0], pBlob)
+ rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
+ capi.SQLITE_WASM_DEALLOC);
+ break;
+ }
+ default:
+ sqlite3.config.warn("Unsupported bind() argument type:",val);
+ toss3("Unsupported bind() argument type: "+(typeof val));
+ }
+ if(rc) DB.checkRc(stmt.db.pointer, rc);
+ stmt._mayGet = false;
+ return stmt;
+ };
+
+ Stmt.prototype = {
+ /**
+ "Finalizes" this statement. This is a no-op if the statement
+ has already been finalized. Returns the result of
+ sqlite3_finalize() (0 on success, non-0 on error), or the
+ undefined value if the statement has already been
+ finalized. Regardless of success or failure, most methods in
+ this class will throw if called after this is.
+
+ This method always throws if called when it is illegal to do
+ so. Namely, when triggered via a per-row callback handler of a
+ DB.exec() call.
+ */
+ finalize: function(){
+ if(this.pointer){
+ affirmNotLockedByExec(this,'finalize()');
+ const rc = capi.sqlite3_finalize(this.pointer);
+ delete __stmtMap.get(this.db)[this.pointer];
+ __ptrMap.delete(this);
+ delete this._mayGet;
+ delete this.parameterCount;
+ delete this._lockedByExec;
+ delete this.db;
+ return rc;
+ }
+ },
+ /**
+ Clears all bound values. Returns this object. Throws if this
+ statement has been finalized or if modification of the
+ statement is currently illegal (e.g. in the per-row callback of
+ a DB.exec() call).
+ */
+ clearBindings: function(){
+ affirmNotLockedByExec(affirmStmtOpen(this), 'clearBindings()')
+ capi.sqlite3_clear_bindings(this.pointer);
+ this._mayGet = false;
+ return this;
+ },
+ /**
+ Resets this statement so that it may be step()ed again from the
+ beginning. Returns this object. Throws if this statement has
+ been finalized, if it may not legally be reset because it is
+ currently being used from a DB.exec() callback, or if the
+ underlying call to sqlite3_reset() returns non-0.
+
+ If passed a truthy argument then this.clearBindings() is
+ also called, otherwise any existing bindings, along with
+ any memory allocated for them, are retained.
+
+ In versions 3.42.0 and earlier, this function did not throw if
+ sqlite3_reset() returns non-0, but it was discovered that
+ throwing (or significant extra client-side code) is necessary
+ in order to avoid certain silent failure scenarios, as
+ discussed at:
+
+ https://sqlite.org/forum/forumpost/36f7a2e7494897df
+ */
+ reset: function(alsoClearBinds){
+ affirmNotLockedByExec(this,'reset()');
+ if(alsoClearBinds) this.clearBindings();
+ const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer);
+ this._mayGet = false;
+ checkSqlite3Rc(this.db, rc);
+ return this;
+ },
+ /**
+ Binds one or more values to its bindable parameters. It
+ accepts 1 or 2 arguments:
+
+ If passed a single argument, it must be either an array, an
+ object, or a value of a bindable type (see below).
+
+ If passed 2 arguments, the first one is the 1-based bind
+ index or bindable parameter name and the second one must be
+ a value of a bindable type.
+
+ Bindable value types:
+
+ - null is bound as NULL.
+
+ - undefined as a standalone value is a no-op intended to
+ simplify certain client-side use cases: passing undefined as
+ a value to this function will not actually bind anything and
+ this function will skip confirmation that binding is even
+ legal. (Those semantics simplify certain client-side uses.)
+ Conversely, a value of undefined as an array or object
+ property when binding an array/object (see below) is treated
+ the same as null.
+
+ - Numbers are bound as either doubles or integers: doubles if
+ they are larger than 32 bits, else double or int32, depending
+ on whether they have a fractional part. Booleans are bound as
+ integer 0 or 1. It is not expected the distinction of binding
+ doubles which have no fractional parts and integers is
+ significant for the majority of clients due to sqlite3's data
+ typing model. If BigInt support is enabled then this routine
+ will bind BigInt values as 64-bit integers if they'll fit in
+ 64 bits. If that support disabled, it will store the BigInt
+ as an int32 or a double if it can do so without loss of
+ precision. If the BigInt is _too BigInt_ then it will throw.
+
+ - Strings are bound as strings (use bindAsBlob() to force
+ blob binding).
+
+ - Uint8Array, Int8Array, and ArrayBuffer instances are bound as
+ blobs.
+
+ If passed an array, each element of the array is bound at
+ the parameter index equal to the array index plus 1
+ (because arrays are 0-based but binding is 1-based).
+
+ If passed an object, each object key is treated as a
+ bindable parameter name. The object keys _must_ match any
+ bindable parameter names, including any `$`, `@`, or `:`
+ prefix. Because `$` is a legal identifier chararacter in
+ JavaScript, that is the suggested prefix for bindable
+ parameters: `stmt.bind({$a: 1, $b: 2})`.
+
+ It returns this object on success and throws on
+ error. Errors include:
+
+ - Any bind index is out of range, a named bind parameter
+ does not match, or this statement has no bindable
+ parameters.
+
+ - Any value to bind is of an unsupported type.
+
+ - Passed no arguments or more than two.
+
+ - The statement has been finalized.
+ */
+ bind: function(/*[ndx,] arg*/){
+ affirmStmtOpen(this);
+ let ndx, arg;
+ switch(arguments.length){
+ case 1: ndx = 1; arg = arguments[0]; break;
+ case 2: ndx = arguments[0]; arg = arguments[1]; break;
+ default: toss3("Invalid bind() arguments.");
+ }
+ if(undefined===arg){
+ /* It might seem intuitive to bind undefined as NULL
+ but this approach simplifies certain client-side
+ uses when passing on arguments between 2+ levels of
+ functions. */
+ return this;
+ }else if(!this.parameterCount){
+ toss3("This statement has no bindable parameters.");
+ }
+ this._mayGet = false;
+ if(null===arg){
+ /* bind NULL */
+ return bindOne(this, ndx, BindTypes.null, arg);
+ }
+ else if(Array.isArray(arg)){
+ /* bind each entry by index */
+ if(1!==arguments.length){
+ toss3("When binding an array, an index argument is not permitted.");
+ }
+ arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
+ return this;
+ }else if(arg instanceof ArrayBuffer){
+ arg = new Uint8Array(arg);
+ }
+ if('object'===typeof arg/*null was checked above*/
+ && !util.isBindableTypedArray(arg)){
+ /* Treat each property of arg as a named bound parameter. */
+ if(1!==arguments.length){
+ toss3("When binding an object, an index argument is not permitted.");
+ }
+ Object.keys(arg)
+ .forEach(k=>bindOne(this, k,
+ affirmSupportedBindType(arg[k]),
+ arg[k]));
+ return this;
+ }else{
+ return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
+ }
+ toss3("Should not reach this point.");
+ },
+ /**
+ Special case of bind() which binds the given value using the
+ BLOB binding mechanism instead of the default selected one for
+ the value. The ndx may be a numbered or named bind index. The
+ value must be of type string, null/undefined (both get treated
+ as null), or a TypedArray of a type supported by the bind()
+ API. This API cannot bind numbers as blobs.
+
+ If passed a single argument, a bind index of 1 is assumed and
+ the first argument is the value.
+ */
+ bindAsBlob: function(ndx,arg){
+ affirmStmtOpen(this);
+ if(1===arguments.length){
+ arg = ndx;
+ ndx = 1;
+ }
+ const t = affirmSupportedBindType(arg);
+ if(BindTypes.string !== t && BindTypes.blob !== t
+ && BindTypes.null !== t){
+ toss3("Invalid value type for bindAsBlob()");
+ }
+ return bindOne(this, ndx, BindTypes.blob, arg);
+ },
+ /**
+ Steps the statement one time. If the result indicates that a
+ row of data is available, a truthy value is returned. If no
+ row of data is available, a falsy value is returned. Throws on
+ error.
+ */
+ step: function(){
+ affirmNotLockedByExec(this, 'step()');
+ const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
+ switch(rc){
+ case capi.SQLITE_DONE: return this._mayGet = false;
+ case capi.SQLITE_ROW: return this._mayGet = true;
+ default:
+ this._mayGet = false;
+ sqlite3.config.warn("sqlite3_step() rc=",rc,
+ capi.sqlite3_js_rc_str(rc),
+ "SQL =", capi.sqlite3_sql(this.pointer));
+ DB.checkRc(this.db.pointer, rc);
+ }
+ },
+ /**
+ Functions exactly like step() except that...
+
+ 1) On success, it calls this.reset() and returns this object.
+
+ 2) On error, it throws and does not call reset().
+
+ This is intended to simplify constructs like:
+
+ ```
+ for(...) {
+ stmt.bind(...).stepReset();
+ }
+ ```
+
+ Note that the reset() call makes it illegal to call this.get()
+ after the step.
+ */
+ stepReset: function(){
+ this.step();
+ return this.reset();
+ },
+ /**
+ Functions like step() except that it calls finalize() on this
+ statement immediately after stepping, even if the step() call
+ throws.
+
+ On success, it returns true if the step indicated that a row of
+ data was available, else it returns a falsy value.
+
+ This is intended to simplify use cases such as:
+
+ ```
+ aDb.prepare("insert into foo(a) values(?)").bind(123).stepFinalize();
+ ```
+ */
+ stepFinalize: function(){
+ try{
+ const rc = this.step();
+ this.reset(/*for INSERT...RETURNING locking case*/);
+ return rc;
+ }finally{
+ try{this.finalize()}
+ catch(e){/*ignored*/}
+ }
+ },
+
+ /**
+ Fetches the value from the given 0-based column index of
+ the current data row, throwing if index is out of range.
+
+ Requires that step() has just returned a truthy value, else
+ an exception is thrown.
+
+ By default it will determine the data type of the result
+ automatically. If passed a second argument, it must be one
+ of the enumeration values for sqlite3 types, which are
+ defined as members of the sqlite3 module: SQLITE_INTEGER,
+ SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
+ except for undefined, will trigger an exception. Passing
+ undefined is the same as not passing a value. It is legal
+ to, e.g., fetch an integer value as a string, in which case
+ sqlite3 will convert the value to a string.
+
+ If ndx is an array, this function behaves a differently: it
+ assigns the indexes of the array, from 0 to the number of
+ result columns, to the values of the corresponding column,
+ and returns that array.
+
+ If ndx is a plain object, this function behaves even
+ differentlier: it assigns the properties of the object to
+ the values of their corresponding result columns and returns
+ that object.
+
+ Blobs are returned as Uint8Array instances.
+
+ Potential TODO: add type ID SQLITE_JSON, which fetches the
+ result as a string and passes it (if it's not null) to
+ JSON.parse(), returning the result of that. Until then,
+ getJSON() can be used for that.
+ */
+ get: function(ndx,asType){
+ if(!affirmStmtOpen(this)._mayGet){
+ toss3("Stmt.step() has not (recently) returned true.");
+ }
+ if(Array.isArray(ndx)){
+ let i = 0;
+ const n = this.columnCount;
+ while(i<n){
+ ndx[i] = this.get(i++);
+ }
+ return ndx;
+ }else if(ndx && 'object'===typeof ndx){
+ let i = 0;
+ const n = this.columnCount;
+ while(i<n){
+ ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++);
+ }
+ return ndx;
+ }
+ affirmColIndex(this, ndx);
+ switch(undefined===asType
+ ? capi.sqlite3_column_type(this.pointer, ndx)
+ : asType){
+ case capi.SQLITE_NULL: return null;
+ case capi.SQLITE_INTEGER:{
+ if(wasm.bigIntEnabled){
+ const rc = capi.sqlite3_column_int64(this.pointer, ndx);
+ if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
+ /* Coerce "normal" number ranges to normal number values,
+ and only return BigInt-type values for numbers out of this
+ range. */
+ return Number(rc).valueOf();
+ }
+ return rc;
+ }else{
+ const rc = capi.sqlite3_column_double(this.pointer, ndx);
+ if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){
+ /* Throwing here is arguable but, since we're explicitly
+ extracting an SQLITE_INTEGER-type value, it seems fair to throw
+ if the extracted number is out of range for that type.
+ This policy may be laxened to simply pass on the number and
+ hope for the best, as the C API would do. */
+ toss3("Integer is out of range for JS integer range: "+rc);
+ }
+ //sqlite3.config.log("get integer rc=",rc,isInt32(rc));
+ return util.isInt32(rc) ? (rc | 0) : rc;
+ }
+ }
+ case capi.SQLITE_FLOAT:
+ return capi.sqlite3_column_double(this.pointer, ndx);
+ case capi.SQLITE_TEXT:
+ return capi.sqlite3_column_text(this.pointer, ndx);
+ case capi.SQLITE_BLOB: {
+ const n = capi.sqlite3_column_bytes(this.pointer, ndx),
+ ptr = capi.sqlite3_column_blob(this.pointer, ndx),
+ rc = new Uint8Array(n);
+ //heap = n ? wasm.heap8() : false;
+ if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0);
+ //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
+ if(n && this.db._blobXfer instanceof Array){
+ /* This is an optimization soley for the
+ Worker-based API. These values will be
+ transfered to the main thread directly
+ instead of being copied. */
+ this.db._blobXfer.push(rc.buffer);
+ }
+ return rc;
+ }
+ default: toss3("Don't know how to translate",
+ "type of result column #"+ndx+".");
+ }
+ toss3("Not reached.");
+ },
+ /** Equivalent to get(ndx) but coerces the result to an
+ integer. */
+ getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)},
+ /** Equivalent to get(ndx) but coerces the result to a
+ float. */
+ getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)},
+ /** Equivalent to get(ndx) but coerces the result to a
+ string. */
+ getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)},
+ /** Equivalent to get(ndx) but coerces the result to a
+ Uint8Array. */
+ getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)},
+ /**
+ A convenience wrapper around get() which fetches the value
+ as a string and then, if it is not null, passes it to
+ JSON.parse(), returning that result. Throws if parsing
+ fails. If the result is null, null is returned. An empty
+ string, on the other hand, will trigger an exception.
+ */
+ getJSON: function(ndx){
+ const s = this.get(ndx, capi.SQLITE_STRING);
+ return null===s ? s : JSON.parse(s);
+ },
+ // Design note: the only reason most of these getters have a 'get'
+ // prefix is for consistency with getVALUE_TYPE(). The latter
+ // arguably really need that prefix for API readability and the
+ // rest arguably don't, but consistency is a powerful thing.
+ /**
+ Returns the result column name of the given index, or
+ throws if index is out of bounds or this statement has been
+ finalized. This can be used without having run step()
+ first.
+ */
+ getColumnName: function(ndx){
+ return capi.sqlite3_column_name(
+ affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx
+ );
+ },
+ /**
+ If this statement potentially has result columns, this function
+ returns an array of all such names. If passed an array, it is
+ used as the target and all names are appended to it. Returns
+ the target array. Throws if this statement cannot have result
+ columns. This object's columnCount property holds the number of
+ columns.
+ */
+ getColumnNames: function(tgt=[]){
+ affirmColIndex(affirmStmtOpen(this),0);
+ const n = this.columnCount;
+ for(let i = 0; i < n; ++i){
+ tgt.push(capi.sqlite3_column_name(this.pointer, i));
+ }
+ return tgt;
+ },
+ /**
+ If this statement has named bindable parameters and the
+ given name matches one, its 1-based bind index is
+ returned. If no match is found, 0 is returned. If it has no
+ bindable parameters, the undefined value is returned.
+ */
+ getParamIndex: function(name){
+ return (affirmStmtOpen(this).parameterCount
+ ? capi.sqlite3_bind_parameter_index(this.pointer, name)
+ : undefined);
+ },
+ /**
+ If this statement has named bindable parameters and the given
+ index refers to one, its name is returned, else null is
+ returned. If this statement has no bound parameters, undefined
+ is returned.
+
+ Added in 3.47.
+ */
+ getParamName: function(ndx){
+ return (affirmStmtOpen(this).parameterCount
+ ? capi.sqlite3_bind_parameter_name(this.pointer, ndx)
+ : undefined);
+ },
+
+ /**
+ Behaves like sqlite3_stmt_busy() but throws if this statement
+ is closed and returns a value of type boolean instead of integer.
+
+ Added in 3.47.
+ */
+ isBusy: function(){
+ return 0!==capi.sqlite3_stmt_busy(affirmStmtOpen(this));
+ },
+
+ /**
+ Behaves like sqlite3_stmt_readonly() but throws if this statement
+ is closed and returns a value of type boolean instead of integer.
+
+ Added in 3.47.
+ */
+ isReadOnly: function(){
+ return 0!==capi.sqlite3_stmt_readonly(affirmStmtOpen(this));
+ }
+ }/*Stmt.prototype*/;
+
+ {/* Add the `pointer` property to DB and Stmt. */
+ const prop = {
+ enumerable: true,
+ get: function(){return __ptrMap.get(this)},
+ set: ()=>toss3("The pointer property is read-only.")
+ }
+ Object.defineProperty(Stmt.prototype, 'pointer', prop);
+ Object.defineProperty(DB.prototype, 'pointer', prop);
+ }
+ /**
+ Stmt.columnCount is an interceptor for sqlite3_column_count().
+
+ This requires an unfortunate performance hit compared to caching
+ columnCount when the Stmt is created/prepared (as was done in
+ SQLite <=3.42.0), but is necessary in order to handle certain
+ corner cases, as described in
+ https://sqlite.org/forum/forumpost/7774b773937cbe0a.
+ */
+ Object.defineProperty(Stmt.prototype, 'columnCount', {
+ enumerable: false,
+ get: function(){return capi.sqlite3_column_count(this.pointer)},
+ set: ()=>toss3("The columnCount property is read-only.")
+ });
+
+ /** The OO API's public namespace. */
+ sqlite3.oo1 = {
+ DB,
+ Stmt
+ }/*oo1 object*/;
+
+ if(util.isUIThread()){
+ /**
+ Functionally equivalent to DB(storageName,'c','kvvfs') except
+ that it throws if the given storage name is not one of 'local'
+ or 'session'.
+
+ As of version 3.46, the argument may optionally be an options
+ object in the form:
+
+ {
+ filename: 'session'|'local',
+ ... etc. (all options supported by the DB ctor)
+ }
+
+ noting that the 'vfs' option supported by main DB
+ constructor is ignored here: the vfs is always 'kvvfs'.
+ */
+ sqlite3.oo1.JsStorageDb = function(storageName='session'){
+ const opt = dbCtorHelper.normalizeArgs(...arguments);
+ storageName = opt.filename;
+ if('session'!==storageName && 'local'!==storageName){
+ toss3("JsStorageDb db name must be one of 'session' or 'local'.");
+ }
+ opt.vfs = 'kvvfs';
+ dbCtorHelper.call(this, opt);
+ };
+ const jdb = sqlite3.oo1.JsStorageDb;
+ jdb.prototype = Object.create(DB.prototype);
+ /** Equivalent to sqlite3_js_kvvfs_clear(). */
+ jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
+ /**
+ Clears this database instance's storage or throws if this
+ instance has been closed. Returns the number of
+ database blocks which were cleaned up.
+ */
+ jdb.prototype.clearStorage = function(){
+ return jdb.clearStorage(affirmDbOpen(this).filename);
+ };
+ /** Equivalent to sqlite3_js_kvvfs_size(). */
+ jdb.storageSize = capi.sqlite3_js_kvvfs_size;
+ /**
+ Returns the _approximate_ number of bytes this database takes
+ up in its storage or throws if this instance has been closed.
+ */
+ jdb.prototype.storageSize = function(){
+ return jdb.storageSize(affirmDbOpen(this).filename);
+ };
+ }/*main-window-only bits*/
+
+});
+/* END FILE: api/sqlite3-api-oo1.c-pp.js */
+/* BEGIN FILE: api/sqlite3-api-worker1.c-pp.js */
+/**
+ 2022-07-22
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file implements the initializer for SQLite's "Worker API #1", a
+ very basic DB access API intended to be scripted from a main window
+ thread via Worker-style messages. Because of limitations in that
+ type of communication, this API is minimalistic and only capable of
+ serving relatively basic DB requests (e.g. it cannot process nested
+ query loops concurrently).
+
+ This file requires that the core C-style sqlite3 API and OO API #1
+ have been loaded.
+*/
+
+/**
+ sqlite3.initWorker1API() implements a Worker-based wrapper around
+ SQLite3 OO API #1, colloquially known as "Worker API #1".
+
+ In order to permit this API to be loaded in worker threads without
+ automatically registering onmessage handlers, initializing the
+ worker API requires calling initWorker1API(). If this function is
+ called from a non-worker thread then it throws an exception. It
+ must only be called once per Worker.
+
+ When initialized, it installs message listeners to receive Worker
+ messages and then it posts a message in the form:
+
+ ```
+ {type:'sqlite3-api', result:'worker1-ready'}
+ ```
+
+ to let the client know that it has been initialized. Clients may
+ optionally depend on this function not returning until
+ initialization is complete, as the initialization is synchronous.
+ In some contexts, however, listening for the above message is
+ a better fit.
+
+ Note that the worker-based interface can be slightly quirky because
+ of its async nature. In particular, any number of messages may be posted
+ to the worker before it starts handling any of them. If, e.g., an
+ "open" operation fails, any subsequent messages will fail. The
+ Promise-based wrapper for this API (`sqlite3-worker1-promiser.js`)
+ is more comfortable to use in that regard.
+
+ The documentation for the input and output worker messages for
+ this API follows...
+
+ ====================================================================
+ Common message format...
+
+ Each message posted to the worker has an operation-independent
+ envelope and operation-dependent arguments:
+
+ ```
+ {
+ type: string, // one of: 'open', 'close', 'exec', 'export', 'config-get'
+
+ messageId: OPTIONAL arbitrary value. The worker will copy it as-is
+ into response messages to assist in client-side dispatching.
+
+ dbId: a db identifier string (returned by 'open') which tells the
+ operation which database instance to work on. If not provided, the
+ first-opened db is used. This is an "opaque" value, with no
+ inherently useful syntax or information. Its value is subject to
+ change with any given build of this API and cannot be used as a
+ basis for anything useful beyond its one intended purpose.
+
+ args: ...operation-dependent arguments...
+
+ // the framework may add other properties for testing or debugging
+ // purposes.
+
+ }
+ ```
+
+ Response messages, posted back to the main thread, look like:
+
+ ```
+ {
+ type: string. Same as above except for error responses, which have the type
+ 'error',
+
+ messageId: same value, if any, provided by the inbound message
+
+ dbId: the id of the db which was operated on, if any, as returned
+ by the corresponding 'open' operation.
+
+ result: ...operation-dependent result...
+
+ }
+ ```
+
+ ====================================================================
+ Error responses
+
+ Errors are reported messages in an operation-independent format:
+
+ ```
+ {
+ type: "error",
+
+ messageId: ...as above...,
+
+ dbId: ...as above...
+
+ result: {
+
+ operation: type of the triggering operation: 'open', 'close', ...
+
+ message: ...error message text...
+
+ errorClass: string. The ErrorClass.name property from the thrown exception.
+
+ input: the message object which triggered the error.
+
+ stack: _if available_, a stack trace array.
+
+ }
+
+ }
+ ```
+
+
+ ====================================================================
+ "config-get"
+
+ This operation fetches the serializable parts of the sqlite3 API
+ configuration.
+
+ Message format:
+
+ ```
+ {
+ type: "config-get",
+ messageId: ...as above...,
+ args: currently ignored and may be elided.
+ }
+ ```
+
+ Response:
+
+ ```
+ {
+ type: "config-get",
+ messageId: ...as above...,
+ result: {
+
+ version: sqlite3.version object
+
+ bigIntEnabled: bool. True if BigInt support is enabled.
+
+ vfsList: result of sqlite3.capi.sqlite3_js_vfs_list()
+ }
+ }
+ ```
+
+
+ ====================================================================
+ "open" a database
+
+ Message format:
+
+ ```
+ {
+ type: "open",
+ messageId: ...as above...,
+ args:{
+
+ filename [=":memory:" or "" (unspecified)]: the db filename.
+ See the sqlite3.oo1.DB constructor for peculiarities and
+ transformations,
+
+ vfs: sqlite3_vfs name. Ignored if filename is ":memory:" or "".
+ This may change how the given filename is resolved.
+ }
+ }
+ ```
+
+ Response:
+
+ ```
+ {
+ type: "open",
+ messageId: ...as above...,
+ result: {
+ filename: db filename, possibly differing from the input.
+
+ dbId: an opaque ID value which must be passed in the message
+ envelope to other calls in this API to tell them which db to
+ use. If it is not provided to future calls, they will default to
+ operating on the least-recently-opened db. This property is, for
+ API consistency's sake, also part of the containing message
+ envelope. Only the `open` operation includes it in the `result`
+ property.
+
+ persistent: true if the given filename resides in the
+ known-persistent storage, else false.
+
+ vfs: name of the VFS the "main" db is using.
+ }
+ }
+ ```
+
+ ====================================================================
+ "close" a database
+
+ Message format:
+
+ ```
+ {
+ type: "close",
+ messageId: ...as above...
+ dbId: ...as above...
+ args: OPTIONAL {unlink: boolean}
+ }
+ ```
+
+ If the `dbId` does not refer to an opened ID, this is a no-op. If
+ the `args` object contains a truthy `unlink` value then the database
+ will be unlinked (deleted) after closing it. The inability to close a
+ db (because it's not opened) or delete its file does not trigger an
+ error.
+
+ Response:
+
+ ```
+ {
+ type: "close",
+ messageId: ...as above...,
+ result: {
+
+ filename: filename of closed db, or undefined if no db was closed
+
+ }
+ }
+ ```
+
+ ====================================================================
+ "exec" SQL
+
+ All SQL execution is processed through the exec operation. It offers
+ most of the features of the oo1.DB.exec() method, with a few limitations
+ imposed by the state having to cross thread boundaries.
+
+ Message format:
+
+ ```
+ {
+ type: "exec",
+ messageId: ...as above...
+ dbId: ...as above...
+ args: string (SQL) or {... see below ...}
+ }
+ ```
+
+ Response:
+
+ ```
+ {
+ type: "exec",
+ messageId: ...as above...,
+ dbId: ...as above...
+ result: {
+ input arguments, possibly modified. See below.
+ }
+ }
+ ```
+
+ The arguments are in the same form accepted by oo1.DB.exec(), with
+ the exceptions noted below.
+
+ If the `countChanges` arguments property (added in version 3.43) is
+ truthy then the `result` property contained by the returned object
+ will have a `changeCount` property which holds the number of changes
+ made by the provided SQL. Because the SQL may contain an arbitrary
+ number of statements, the `changeCount` is calculated by calling
+ `sqlite3_total_changes()` before and after the SQL is evaluated. If
+ the value of `countChanges` is 64 then the `changeCount` property
+ will be returned as a 64-bit integer in the form of a BigInt (noting
+ that that will trigger an exception if used in a BigInt-incapable
+ build). In the latter case, the number of changes is calculated by
+ calling `sqlite3_total_changes64()` before and after the SQL is
+ evaluated.
+
+ A function-type args.callback property cannot cross
+ the window/Worker boundary, so is not useful here. If
+ args.callback is a string then it is assumed to be a
+ message type key, in which case a callback function will be
+ applied which posts each row result via:
+
+ postMessage({type: thatKeyType,
+ rowNumber: 1-based-#,
+ row: theRow,
+ columnNames: anArray
+ })
+
+ And, at the end of the result set (whether or not any result rows
+ were produced), it will post an identical message with
+ (row=undefined, rowNumber=null) to alert the caller than the result
+ set is completed. Note that a row value of `null` is a legal row
+ result for certain arg.rowMode values.
+
+ (Design note: we don't use (row=undefined, rowNumber=undefined) to
+ indicate end-of-results because fetching those would be
+ indistinguishable from fetching from an empty object unless the
+ client used hasOwnProperty() (or similar) to distinguish "missing
+ property" from "property with the undefined value". Similarly,
+ `null` is a legal value for `row` in some case , whereas the db
+ layer won't emit a result value of `undefined`.)
+
+ The callback proxy must not recurse into this interface. An exec()
+ call will tie up the Worker thread, causing any recursion attempt
+ to wait until the first exec() is completed.
+
+ The response is the input options object (or a synthesized one if
+ passed only a string), noting that options.resultRows and
+ options.columnNames may be populated by the call to db.exec().
+
+
+ ====================================================================
+ "export" the current db
+
+ To export the underlying database as a byte array...
+
+ Message format:
+
+ ```
+ {
+ type: "export",
+ messageId: ...as above...,
+ dbId: ...as above...
+ }
+ ```
+
+ Response:
+
+ ```
+ {
+ type: "export",
+ messageId: ...as above...,
+ dbId: ...as above...
+ result: {
+ byteArray: Uint8Array (as per sqlite3_js_db_export()),
+ filename: the db filename,
+ mimetype: "application/x-sqlite3"
+ }
+ }
+ ```
+
+*/
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+const util = sqlite3.util;
+sqlite3.initWorker1API = function(){
+ 'use strict';
+ const toss = (...args)=>{throw new Error(args.join(' '))};
+ if(!(globalThis.WorkerGlobalScope instanceof Function)){
+ toss("initWorker1API() must be run from a Worker thread.");
+ }
+ const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object.");
+ const DB = sqlite3.oo1.DB;
+
+ /**
+ Returns the app-wide unique ID for the given db, creating one if
+ needed.
+ */
+ const getDbId = function(db){
+ let id = wState.idMap.get(db);
+ if(id) return id;
+ id = 'db#'+(++wState.idSeq)+'@'+db.pointer;
+ /** ^^^ can't simply use db.pointer b/c closing/opening may re-use
+ the same address, which could map pending messages to a wrong
+ instance. */
+ wState.idMap.set(db, id);
+ return id;
+ };
+
+ /**
+ Internal helper for managing Worker-level state.
+ */
+ const wState = {
+ /**
+ Each opened DB is added to this.dbList, and the first entry in
+ that list is the default db. As each db is closed, its entry is
+ removed from the list.
+ */
+ dbList: [],
+ /** Sequence number of dbId generation. */
+ idSeq: 0,
+ /** Map of DB instances to dbId. */
+ idMap: new WeakMap,
+ /** Temp holder for "transferable" postMessage() state. */
+ xfer: [],
+ open: function(opt){
+ const db = new DB(opt);
+ this.dbs[getDbId(db)] = db;
+ if(this.dbList.indexOf(db)<0) this.dbList.push(db);
+ return db;
+ },
+ close: function(db,alsoUnlink){
+ if(db){
+ delete this.dbs[getDbId(db)];
+ const filename = db.filename;
+ const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0);
+ db.close();
+ const ddNdx = this.dbList.indexOf(db);
+ if(ddNdx>=0) this.dbList.splice(ddNdx, 1);
+ if(alsoUnlink && filename && pVfs){
+ util.sqlite3__wasm_vfs_unlink(pVfs, filename);
+ }
+ }
+ },
+ /**
+ Posts the given worker message value. If xferList is provided,
+ it must be an array, in which case a copy of it passed as
+ postMessage()'s second argument and xferList.length is set to
+ 0.
+ */
+ post: function(msg,xferList){
+ if(xferList && xferList.length){
+ globalThis.postMessage( msg, Array.from(xferList) );
+ xferList.length = 0;
+ }else{
+ globalThis.postMessage(msg);
+ }
+ },
+ /** Map of DB IDs to DBs. */
+ dbs: Object.create(null),
+ /** Fetch the DB for the given id. Throw if require=true and the
+ id is not valid, else return the db or undefined. */
+ getDb: function(id,require=true){
+ return this.dbs[id]
+ || (require ? toss("Unknown (or closed) DB ID:",id) : undefined);
+ }
+ };
+
+ /** Throws if the given db is falsy or not opened, else returns its
+ argument. */
+ const affirmDbOpen = function(db = wState.dbList[0]){
+ return (db && db.pointer) ? db : toss("DB is not opened.");
+ };
+
+ /** Extract dbId from the given message payload. */
+ const getMsgDb = function(msgData,affirmExists=true){
+ const db = wState.getDb(msgData.dbId,false) || wState.dbList[0];
+ return affirmExists ? affirmDbOpen(db) : db;
+ };
+
+ const getDefaultDbId = function(){
+ return wState.dbList[0] && getDbId(wState.dbList[0]);
+ };
+
+ const isSpecialDbFilename = (n)=>{
+ return ""===n || ':'===n[0];
+ };
+
+ /**
+ A level of "organizational abstraction" for the Worker1
+ API. Each method in this object must map directly to a Worker1
+ message type key. The onmessage() dispatcher attempts to
+ dispatch all inbound messages to a method of this object,
+ passing it the event.data part of the inbound event object. All
+ methods must return a plain Object containing any result
+ state, which the dispatcher may amend. All methods must throw
+ on error.
+ */
+ const wMsgHandler = {
+ open: function(ev){
+ const oargs = Object.create(null), args = (ev.args || Object.create(null));
+ if(args.simulateError){ // undocumented internal testing option
+ toss("Throwing because of simulateError flag.");
+ }
+ const rc = Object.create(null);
+ oargs.vfs = args.vfs;
+ oargs.filename = args.filename || "";
+ const db = wState.open(oargs);
+ rc.filename = db.filename;
+ rc.persistent = !!sqlite3.capi.sqlite3_js_db_uses_vfs(db.pointer, "opfs");
+ rc.dbId = getDbId(db);
+ rc.vfs = db.dbVfsName();
+ return rc;
+ },
+
+ close: function(ev){
+ const db = getMsgDb(ev,false);
+ const response = {
+ filename: db && db.filename
+ };
+ if(db){
+ const doUnlink = ((ev.args && 'object'===typeof ev.args)
+ ? !!ev.args.unlink : false);
+ wState.close(db, doUnlink);
+ }
+ return response;
+ },
+
+ exec: function(ev){
+ const rc = (
+ 'string'===typeof ev.args
+ ) ? {sql: ev.args} : (ev.args || Object.create(null));
+ if('stmt'===rc.rowMode){
+ toss("Invalid rowMode for 'exec': stmt mode",
+ "does not work in the Worker API.");
+ }else if(!rc.sql){
+ toss("'exec' requires input SQL.");
+ }
+ const db = getMsgDb(ev);
+ if(rc.callback || Array.isArray(rc.resultRows)){
+ // Part of a copy-avoidance optimization for blobs
+ db._blobXfer = wState.xfer;
+ }
+ const theCallback = rc.callback;
+ let rowNumber = 0;
+ const hadColNames = !!rc.columnNames;
+ if('string' === typeof theCallback){
+ if(!hadColNames) rc.columnNames = [];
+ /* Treat this as a worker message type and post each
+ row as a message of that type. */
+ rc.callback = function(row,stmt){
+ wState.post({
+ type: theCallback,
+ columnNames: rc.columnNames,
+ rowNumber: ++rowNumber,
+ row: row
+ }, wState.xfer);
+ }
+ }
+ try {
+ const changeCount = !!rc.countChanges
+ ? db.changes(true,(64===rc.countChanges))
+ : undefined;
+ db.exec(rc);
+ if(undefined !== changeCount){
+ rc.changeCount = db.changes(true,64===rc.countChanges) - changeCount;
+ }
+ if(rc.callback instanceof Function){
+ rc.callback = theCallback;
+ /* Post a sentinel message to tell the client that the end
+ of the result set has been reached (possibly with zero
+ rows). */
+ wState.post({
+ type: theCallback,
+ columnNames: rc.columnNames,
+ rowNumber: null /*null to distinguish from "property not set"*/,
+ row: undefined /*undefined because null is a legal row value
+ for some rowType values, but undefined is not*/
+ });
+ }
+ }finally{
+ delete db._blobXfer;
+ if(rc.callback) rc.callback = theCallback;
+ }
+ return rc;
+ }/*exec()*/,
+
+ 'config-get': function(){
+ const rc = Object.create(null), src = sqlite3.config;
+ [
+ 'bigIntEnabled'
+ ].forEach(function(k){
+ if(Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k];
+ });
+ rc.version = sqlite3.version;
+ rc.vfsList = sqlite3.capi.sqlite3_js_vfs_list();
+ return rc;
+ },
+
+ /**
+ Exports the database to a byte array, as per
+ sqlite3_serialize(). Response is an object:
+
+ {
+ byteArray: Uint8Array (db file contents),
+ filename: the current db filename,
+ mimetype: 'application/x-sqlite3'
+ }
+ */
+ export: function(ev){
+ const db = getMsgDb(ev);
+ const response = {
+ byteArray: sqlite3.capi.sqlite3_js_db_export(db.pointer),
+ filename: db.filename,
+ mimetype: 'application/x-sqlite3'
+ };
+ wState.xfer.push(response.byteArray.buffer);
+ return response;
+ }/*export()*/,
+
+ toss: function(ev){
+ toss("Testing worker exception");
+ }
+ }/*wMsgHandler*/;
+
+ globalThis.onmessage = async function(ev){
+ ev = ev.data;
+ let result, dbId = ev.dbId, evType = ev.type;
+ const arrivalTime = performance.now();
+ try {
+ if(wMsgHandler.hasOwnProperty(evType) &&
+ wMsgHandler[evType] instanceof Function){
+ result = await wMsgHandler[evType](ev);
+ }else{
+ toss("Unknown db worker message type:",ev.type);
+ }
+ }catch(err){
+ evType = 'error';
+ result = {
+ operation: ev.type,
+ message: err.message,
+ errorClass: err.name,
+ input: ev
+ };
+ if(err.stack){
+ result.stack = ('string'===typeof err.stack)
+ ? err.stack.split(/\n\s*/) : err.stack;
+ }
+ if(0) sqlite3.config.warn("Worker is propagating an exception to main thread.",
+ "Reporting it _here_ for the stack trace:",err,result);
+ }
+ if(!dbId){
+ dbId = result.dbId/*from 'open' cmd*/
+ || getDefaultDbId();
+ }
+ // Timing info is primarily for use in testing this API. It's not part of
+ // the public API. arrivalTime = when the worker got the message.
+ wState.post({
+ type: evType,
+ dbId: dbId,
+ messageId: ev.messageId,
+ workerReceivedTime: arrivalTime,
+ workerRespondTime: performance.now(),
+ departureTime: ev.departureTime,
+ // TODO: move the timing bits into...
+ //timing:{
+ // departure: ev.departureTime,
+ // workerReceived: arrivalTime,
+ // workerResponse: performance.now();
+ //},
+ result: result
+ }, wState.xfer);
+ };
+ globalThis.postMessage({type:'sqlite3-api',result:'worker1-ready'});
+}.bind({sqlite3});
+});
+/* END FILE: api/sqlite3-api-worker1.c-pp.js */
+/* BEGIN FILE: api/sqlite3-vfs-helper.c-pp.js */
+/*
+** 2022-11-30
+**
+** The author disclaims copyright to this source code. In place of a
+** legal notice, here is a blessing:
+**
+** * May you do good and not evil.
+** * May you find forgiveness for yourself and forgive others.
+** * May you share freely, never taking more than you give.
+*/
+
+/**
+ This file installs sqlite3.vfs, a namespace of helpers for use in
+ the creation of JavaScript implementations of sqlite3_vfs.
+*/
+'use strict';
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
+ const vfs = Object.create(null);
+ sqlite3.vfs = vfs;
+
+ /**
+ Uses sqlite3_vfs_register() to register this
+ sqlite3.capi.sqlite3_vfs instance. This object must have already
+ been filled out properly. If the first argument is truthy, the
+ VFS is registered as the default VFS, else it is not.
+
+ On success, returns this object. Throws on error.
+ */
+ capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
+ if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
+ toss("Expecting a sqlite3_vfs-type argument.");
+ }
+ const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
+ if(rc){
+ toss("sqlite3_vfs_register(",this,") failed with rc",rc);
+ }
+ if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
+ toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
+ this);
+ }
+ return this;
+ };
+
+ /**
+ A wrapper for
+ sqlite3.StructBinder.StructType.prototype.installMethods() or
+ registerVfs() to reduce installation of a VFS and/or its I/O
+ methods to a single call.
+
+ Accepts an object which contains the properties "io" and/or
+ "vfs", each of which is itself an object with following properties:
+
+ - `struct`: an sqlite3.StructBinder.StructType-type struct. This
+ must be a populated (except for the methods) object of type
+ sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
+ "vfs" entry).
+
+ - `methods`: an object mapping sqlite3_io_methods method names
+ (e.g. 'xClose') to JS implementations of those methods. The JS
+ implementations must be call-compatible with their native
+ counterparts.
+
+ For each of those object, this function passes its (`struct`,
+ `methods`, (optional) `applyArgcCheck`) properties to
+ installMethods().
+
+ If the `vfs` entry is set then:
+
+ - Its `struct` property's registerVfs() is called. The
+ `vfs` entry may optionally have an `asDefault` property, which
+ gets passed as the argument to registerVfs().
+
+ - If `struct.$zName` is falsy and the entry has a string-type
+ `name` property, `struct.$zName` is set to the C-string form of
+ that `name` value before registerVfs() is called. That string
+ gets added to the on-dispose state of the struct.
+
+ On success returns this object. Throws on error.
+ */
+ vfs.installVfs = function(opt){
+ let count = 0;
+ const propList = ['io','vfs'];
+ for(const key of propList){
+ const o = opt[key];
+ if(o){
+ ++count;
+ o.struct.installMethods(o.methods, !!o.applyArgcCheck);
+ if('vfs'===key){
+ if(!o.struct.$zName && 'string'===typeof o.name){
+ o.struct.addOnDispose(
+ o.struct.$zName = wasm.allocCString(o.name)
+ );
+ }
+ o.struct.registerVfs(!!o.asDefault);
+ }
+ }
+ }
+ if(!count) toss("Misuse: installVfs() options object requires at least",
+ "one of:", propList);
+ return this;
+ };
+}/*sqlite3ApiBootstrap.initializers.push()*/);
+/* END FILE: api/sqlite3-vfs-helper.c-pp.js */
+/* BEGIN FILE: api/sqlite3-vtab-helper.c-pp.js */
+/*
+** 2022-11-30
+**
+** The author disclaims copyright to this source code. In place of a
+** legal notice, here is a blessing:
+**
+** * May you do good and not evil.
+** * May you find forgiveness for yourself and forgive others.
+** * May you share freely, never taking more than you give.
+*/
+
+/**
+ This file installs sqlite3.vtab, a namespace of helpers for use in
+ the creation of JavaScript implementations virtual tables. If built
+ without virtual table support then this function does nothing.
+*/
+'use strict';
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ if( !sqlite3.wasm.exports.sqlite3_declare_vtab ){
+ return;
+ }
+ const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
+ const vtab = Object.create(null);
+ sqlite3.vtab = vtab;
+
+ const sii = capi.sqlite3_index_info;
+ /**
+ If n is >=0 and less than this.$nConstraint, this function
+ returns either a WASM pointer to the 0-based nth entry of
+ this.$aConstraint (if passed a truthy 2nd argument) or an
+ sqlite3_index_info.sqlite3_index_constraint object wrapping that
+ address (if passed a falsy value or no 2nd argument). Returns a
+ falsy value if n is out of range.
+ */
+ sii.prototype.nthConstraint = function(n, asPtr=false){
+ if(n<0 || n>=this.$nConstraint) return false;
+ const ptr = this.$aConstraint + (
+ sii.sqlite3_index_constraint.structInfo.sizeof * n
+ );
+ return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr);
+ };
+
+ /**
+ Works identically to nthConstraint() but returns state from
+ this.$aConstraintUsage, so returns an
+ sqlite3_index_info.sqlite3_index_constraint_usage instance
+ if passed no 2nd argument or a falsy 2nd argument.
+ */
+ sii.prototype.nthConstraintUsage = function(n, asPtr=false){
+ if(n<0 || n>=this.$nConstraint) return false;
+ const ptr = this.$aConstraintUsage + (
+ sii.sqlite3_index_constraint_usage.structInfo.sizeof * n
+ );
+ return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr);
+ };
+
+ /**
+ If n is >=0 and less than this.$nOrderBy, this function
+ returns either a WASM pointer to the 0-based nth entry of
+ this.$aOrderBy (if passed a truthy 2nd argument) or an
+ sqlite3_index_info.sqlite3_index_orderby object wrapping that
+ address (if passed a falsy value or no 2nd argument). Returns a
+ falsy value if n is out of range.
+ */
+ sii.prototype.nthOrderBy = function(n, asPtr=false){
+ if(n<0 || n>=this.$nOrderBy) return false;
+ const ptr = this.$aOrderBy + (
+ sii.sqlite3_index_orderby.structInfo.sizeof * n
+ );
+ return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr);
+ };
+
+ /**
+ Internal factory function for xVtab and xCursor impls.
+ */
+ const __xWrapFactory = function(methodName,StructType){
+ return function(ptr,removeMapping=false){
+ if(0===arguments.length) ptr = new StructType;
+ if(ptr instanceof StructType){
+ //T.assert(!this.has(ptr.pointer));
+ this.set(ptr.pointer, ptr);
+ return ptr;
+ }else if(!wasm.isPtr(ptr)){
+ sqlite3.SQLite3Error.toss("Invalid argument to",methodName+"()");
+ }
+ let rc = this.get(ptr);
+ if(removeMapping) this.delete(ptr);
+ return rc;
+ }.bind(new Map);
+ };
+
+ /**
+ A factory function which implements a simple lifetime manager for
+ mappings between C struct pointers and their JS-level wrappers.
+ The first argument must be the logical name of the manager
+ (e.g. 'xVtab' or 'xCursor'), which is only used for error
+ reporting. The second must be the capi.XYZ struct-type value,
+ e.g. capi.sqlite3_vtab or capi.sqlite3_vtab_cursor.
+
+ Returns an object with 4 methods: create(), get(), unget(), and
+ dispose(), plus a StructType member with the value of the 2nd
+ argument. The methods are documented in the body of this
+ function.
+ */
+ const StructPtrMapper = function(name, StructType){
+ const __xWrap = __xWrapFactory(name,StructType);
+ /**
+ This object houses a small API for managing mappings of (`T*`)
+ to StructType<T> objects, specifically within the lifetime
+ requirements of sqlite3_module methods.
+ */
+ return Object.assign(Object.create(null),{
+ /** The StructType object for this object's API. */
+ StructType,
+ /**
+ Creates a new StructType object, writes its `pointer`
+ value to the given output pointer, and returns that
+ object. Its intended usage depends on StructType:
+
+ sqlite3_vtab: to be called from sqlite3_module::xConnect()
+ or xCreate() implementations.
+
+ sqlite3_vtab_cursor: to be called from xOpen().
+
+ This will throw if allocation of the StructType instance
+ fails or if ppOut is not a pointer-type value.
+ */
+ create: (ppOut)=>{
+ const rc = __xWrap();
+ wasm.pokePtr(ppOut, rc.pointer);
+ return rc;
+ },
+ /**
+ Returns the StructType object previously mapped to the
+ given pointer using create(). Its intended usage depends
+ on StructType:
+
+ sqlite3_vtab: to be called from sqlite3_module methods which
+ take a (sqlite3_vtab*) pointer _except_ for
+ xDestroy()/xDisconnect(), in which case unget() or dispose().
+
+ sqlite3_vtab_cursor: to be called from any sqlite3_module methods
+ which take a `sqlite3_vtab_cursor*` argument except xClose(),
+ in which case use unget() or dispose().
+
+ Rule to remember: _never_ call dispose() on an instance
+ returned by this function.
+ */
+ get: (pCObj)=>__xWrap(pCObj),
+ /**
+ Identical to get() but also disconnects the mapping between the
+ given pointer and the returned StructType object, such that
+ future calls to this function or get() with the same pointer
+ will return the undefined value. Its intended usage depends
+ on StructType:
+
+ sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or
+ xDestroy() implementations or in error handling of a failed
+ xCreate() or xConnect().
+
+ sqlite3_vtab_cursor: to be called from xClose() or during
+ cleanup in a failed xOpen().
+
+ Calling this method obligates the caller to call dispose() on
+ the returned object when they're done with it.
+ */
+ unget: (pCObj)=>__xWrap(pCObj,true),
+ /**
+ Works like unget() plus it calls dispose() on the
+ StructType object.
+ */
+ dispose: (pCObj)=>{
+ const o = __xWrap(pCObj,true);
+ if(o) o.dispose();
+ }
+ });
+ };
+
+ /**
+ A lifetime-management object for mapping `sqlite3_vtab*`
+ instances in sqlite3_module methods to capi.sqlite3_vtab
+ objects.
+
+ The API docs are in the API-internal StructPtrMapper().
+ */
+ vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);
+
+ /**
+ A lifetime-management object for mapping `sqlite3_vtab_cursor*`
+ instances in sqlite3_module methods to capi.sqlite3_vtab_cursor
+ objects.
+
+ The API docs are in the API-internal StructPtrMapper().
+ */
+ vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);
+
+ /**
+ Convenience form of creating an sqlite3_index_info wrapper,
+ intended for use in xBestIndex implementations. Note that the
+ caller is expected to call dispose() on the returned object
+ before returning. Though not _strictly_ required, as that object
+ does not own the pIdxInfo memory, it is nonetheless good form.
+ */
+ vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
+
+ /**
+ Given an sqlite3_module method name and error object, this
+ function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof
+ sqlite3.WasmAllocError), else it returns its second argument. Its
+ intended usage is in the methods of a sqlite3_vfs or
+ sqlite3_module:
+
+ ```
+ try{
+ let rc = ...
+ return rc;
+ }catch(e){
+ return sqlite3.vtab.xError(
+ 'xColumn', e, sqlite3.capi.SQLITE_XYZ);
+ // where SQLITE_XYZ is some call-appropriate result code.
+ }
+ ```
+
+ If no 3rd argument is provided, its default depends on
+ the error type:
+
+ - An sqlite3.WasmAllocError always resolves to capi.SQLITE_NOMEM.
+
+ - If err is an SQLite3Error then its `resultCode` property
+ is used.
+
+ - If all else fails, capi.SQLITE_ERROR is used.
+
+ If xError.errorReporter is a function, it is called in
+ order to report the error, else the error is not reported.
+ If that function throws, that exception is ignored.
+ */
+ vtab.xError = function f(methodName, err, defaultRc){
+ if(f.errorReporter instanceof Function){
+ try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);}
+ catch(e){/*ignored*/}
+ }
+ let rc;
+ if(err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM;
+ else if(arguments.length>2) rc = defaultRc;
+ else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
+ return rc || capi.SQLITE_ERROR;
+ };
+ vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;
+
+ /**
+ A helper for sqlite3_vtab::xRowid() and xUpdate()
+ implementations. It must be passed the final argument to one of
+ those methods (an output pointer to an int64 row ID) and the
+ value to store at the output pointer's address. Returns the same
+ as wasm.poke() and will throw if the 1st or 2nd arguments
+ are invalid for that function.
+
+ Example xRowid impl:
+
+ ```
+ const xRowid = (pCursor, ppRowid64)=>{
+ const c = vtab.xCursor(pCursor);
+ vtab.xRowid(ppRowid64, c.myRowId);
+ return 0;
+ };
+ ```
+ */
+ vtab.xRowid = (ppRowid64, value)=>wasm.poke(ppRowid64, value, 'i64');
+
+ /**
+ A helper to initialize and set up an sqlite3_module object for
+ later installation into individual databases using
+ sqlite3_create_module(). Requires an object with the following
+ properties:
+
+ - `methods`: an object containing a mapping of properties with
+ the C-side names of the sqlite3_module methods, e.g. xCreate,
+ xBestIndex, etc., to JS implementations for those functions.
+ Certain special-case handling is performed, as described below.
+
+ - `catchExceptions` (default=false): if truthy, the given methods
+ are not mapped as-is, but are instead wrapped inside wrappers
+ which translate exceptions into result codes of SQLITE_ERROR or
+ SQLITE_NOMEM, depending on whether the exception is an
+ sqlite3.WasmAllocError. In the case of the xConnect and xCreate
+ methods, the exception handler also sets the output error
+ string to the exception's error string.
+
+ - OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If
+ not set, one will be created automatically. If the current
+ "this" is-a sqlite3_module then it is unconditionally used in
+ place of `struct`.
+
+ - OPTIONAL `iVersion`: if set, it must be an integer value and it
+ gets assigned to the `$iVersion` member of the struct object.
+ If it's _not_ set, and the passed-in `struct` object's `$iVersion`
+ is 0 (the default) then this function attempts to define a value
+ for that property based on the list of methods it has.
+
+ If `catchExceptions` is false, it is up to the client to ensure
+ that no exceptions escape the methods, as doing so would move
+ them through the C API, leading to undefined
+ behavior. (vtab.xError() is intended to assist in reporting
+ such exceptions.)
+
+ Certain methods may refer to the same implementation. To simplify
+ the definition of such methods:
+
+ - If `methods.xConnect` is `true` then the value of
+ `methods.xCreate` is used in its place, and vice versa. sqlite
+ treats xConnect/xCreate functions specially if they are exactly
+ the same function (same pointer value).
+
+ - If `methods.xDisconnect` is true then the value of
+ `methods.xDestroy` is used in its place, and vice versa.
+
+ This is to facilitate creation of those methods inline in the
+ passed-in object without requiring the client to explicitly get a
+ reference to one of them in order to assign it to the other
+ one.
+
+ The `catchExceptions`-installed handlers will account for
+ identical references to the above functions and will install the
+ same wrapper function for both.
+
+ The given methods are expected to return integer values, as
+ expected by the C API. If `catchExceptions` is truthy, the return
+ value of the wrapped function will be used as-is and will be
+ translated to 0 if the function returns a falsy value (e.g. if it
+ does not have an explicit return). If `catchExceptions` is _not_
+ active, the method implementations must explicitly return integer
+ values.
+
+ Throws on error. On success, returns the sqlite3_module object
+ (`this` or `opt.struct` or a new sqlite3_module instance,
+ depending on how it's called).
+ */
+ vtab.setupModule = function(opt){
+ let createdMod = false;
+ const mod = (this instanceof capi.sqlite3_module)
+ ? this : (opt.struct || (createdMod = new capi.sqlite3_module()));
+ try{
+ const methods = opt.methods || toss("Missing 'methods' object.");
+ for(const e of Object.entries({
+ // -----^ ==> [k,v] triggers a broken code transformation in
+ // some versions of the emsdk toolchain.
+ xConnect: 'xCreate', xDisconnect: 'xDestroy'
+ })){
+ // Remap X=true to X=Y for certain X/Y combinations
+ const k = e[0], v = e[1];
+ if(true === methods[k]) methods[k] = methods[v];
+ else if(true === methods[v]) methods[v] = methods[k];
+ }
+ if(opt.catchExceptions){
+ const fwrap = function(methodName, func){
+ if(['xConnect','xCreate'].indexOf(methodName) >= 0){
+ return function(pDb, pAux, argc, argv, ppVtab, pzErr){
+ try{return func(...arguments) || 0}
+ catch(e){
+ if(!(e instanceof sqlite3.WasmAllocError)){
+ wasm.dealloc(wasm.peekPtr(pzErr));
+ wasm.pokePtr(pzErr, wasm.allocCString(e.message));
+ }
+ return vtab.xError(methodName, e);
+ }
+ };
+ }else{
+ return function(...args){
+ try{return func(...args) || 0}
+ catch(e){
+ return vtab.xError(methodName, e);
+ }
+ };
+ }
+ };
+ const mnames = [
+ 'xCreate', 'xConnect', 'xBestIndex', 'xDisconnect',
+ 'xDestroy', 'xOpen', 'xClose', 'xFilter', 'xNext',
+ 'xEof', 'xColumn', 'xRowid', 'xUpdate',
+ 'xBegin', 'xSync', 'xCommit', 'xRollback',
+ 'xFindFunction', 'xRename', 'xSavepoint', 'xRelease',
+ 'xRollbackTo', 'xShadowName'
+ ];
+ const remethods = Object.create(null);
+ for(const k of mnames){
+ const m = methods[k];
+ if(!(m instanceof Function)) continue;
+ else if('xConnect'===k && methods.xCreate===m){
+ remethods[k] = methods.xCreate;
+ }else if('xCreate'===k && methods.xConnect===m){
+ remethods[k] = methods.xConnect;
+ }else{
+ remethods[k] = fwrap(k, m);
+ }
+ }
+ mod.installMethods(remethods, false);
+ }else{
+ // No automatic exception handling. Trust the client
+ // to not throw.
+ mod.installMethods(
+ methods, !!opt.applyArgcCheck/*undocumented option*/
+ );
+ }
+ if(0===mod.$iVersion){
+ let v;
+ if('number'===typeof opt.iVersion) v = opt.iVersion;
+ else if(mod.$xShadowName) v = 3;
+ else if(mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2;
+ else v = 1;
+ mod.$iVersion = v;
+ }
+ }catch(e){
+ if(createdMod) createdMod.dispose();
+ throw e;
+ }
+ return mod;
+ }/*setupModule()*/;
+
+ /**
+ Equivalent to calling vtab.setupModule() with this sqlite3_module
+ object as the call's `this`.
+ */
+ capi.sqlite3_module.prototype.setupModule = function(opt){
+ return vtab.setupModule.call(this, opt);
+ };
+}/*sqlite3ApiBootstrap.initializers.push()*/);
+/* END FILE: api/sqlite3-vtab-helper.c-pp.js */
+/* BEGIN FILE: api/sqlite3-vfs-opfs.c-pp.js */
+/*
+ 2022-09-18
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file holds the synchronous half of an sqlite3_vfs
+ implementation which proxies, in a synchronous fashion, the
+ asynchronous Origin-Private FileSystem (OPFS) APIs using a second
+ Worker, implemented in sqlite3-opfs-async-proxy.js. This file is
+ intended to be appended to the main sqlite3 JS deliverable somewhere
+ after sqlite3-api-oo1.js and before sqlite3-api-cleanup.js.
+*/
+'use strict';
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+/**
+ installOpfsVfs() returns a Promise which, on success, installs an
+ sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs
+ which accept a VFS. It is intended to be called via
+ sqlite3ApiBootstrap.initializers or an equivalent mechanism.
+
+ The installed VFS uses the Origin-Private FileSystem API for
+ all file storage. On error it is rejected with an exception
+ explaining the problem. Reasons for rejection include, but are
+ not limited to:
+
+ - The counterpart Worker (see below) could not be loaded.
+
+ - The environment does not support OPFS. That includes when
+ this function is called from the main window thread.
+
+ Significant notes and limitations:
+
+ - The OPFS features used here are only available in dedicated Worker
+ threads. This file tries to detect that case, resulting in a
+ rejected Promise if those features do not seem to be available.
+
+ - It requires the SharedArrayBuffer and Atomics classes, and the
+ former is only available if the HTTP server emits the so-called
+ COOP and COEP response headers. These features are required for
+ proxying OPFS's synchronous API via the synchronous interface
+ required by the sqlite3_vfs API.
+
+ - This function may only be called a single time. When called, this
+ function removes itself from the sqlite3 object.
+
+ All arguments to this function are for internal/development purposes
+ only. They do not constitute a public API and may change at any
+ time.
+
+ The argument may optionally be a plain object with the following
+ configuration options:
+
+ - proxyUri: name of the async proxy JS file.
+
+ - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables
+ logging of errors. 2 enables logging of warnings and errors. 3
+ additionally enables debugging info. Logging is performed
+ via the sqlite3.config.{log|warn|error}() functions.
+
+ - sanityChecks (=false): if true, some basic sanity tests are run on
+ the OPFS VFS API after it's initialized, before the returned
+ Promise resolves. This is only intended for testing and
+ development of the VFS, not client-side use.
+
+ On success, the Promise resolves to the top-most sqlite3 namespace
+ object and that object gets a new object installed in its
+ `opfs` property, containing several OPFS-specific utilities.
+*/
+const installOpfsVfs = function callee(options){
+ if(!globalThis.SharedArrayBuffer
+ || !globalThis.Atomics){
+ return Promise.reject(
+ new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+
+ "The server must emit the COOP/COEP response headers to enable those. "+
+ "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep")
+ );
+ }else if('undefined'===typeof WorkerGlobalScope){
+ return Promise.reject(
+ new Error("The OPFS sqlite3_vfs cannot run in the main thread "+
+ "because it requires Atomics.wait().")
+ );
+ }else if(!globalThis.FileSystemHandle ||
+ !globalThis.FileSystemDirectoryHandle ||
+ !globalThis.FileSystemFileHandle ||
+ !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle ||
+ !navigator?.storage?.getDirectory){
+ return Promise.reject(
+ new Error("Missing required OPFS APIs.")
+ );
+ }
+ if(!options || 'object'!==typeof options){
+ options = Object.create(null);
+ }
+ const urlParams = new URL(globalThis.location.href).searchParams;
+ if(urlParams.has('opfs-disable')){
+ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.');
+ return Promise.resolve(sqlite3);
+ }
+ if(undefined===options.verbose){
+ options.verbose = urlParams.has('opfs-verbose')
+ ? (+urlParams.get('opfs-verbose') || 2) : 1;
+ }
+ if(undefined===options.sanityChecks){
+ options.sanityChecks = urlParams.has('opfs-sanity-check');
+ }
+ if(undefined===options.proxyUri){
+ options.proxyUri = callee.defaultProxyUri;
+ }
+
+ //sqlite3.config.warn("OPFS options =",options,globalThis.location);
+
+ if('function' === typeof options.proxyUri){
+ options.proxyUri = options.proxyUri();
+ }
+ const thePromise = new Promise(function(promiseResolve_, promiseReject_){
+ const loggers = [
+ sqlite3.config.error,
+ sqlite3.config.warn,
+ sqlite3.config.log
+ ];
+ const logImpl = (level,...args)=>{
+ if(options.verbose>level) loggers[level]("OPFS syncer:",...args);
+ };
+ const log = (...args)=>logImpl(2, ...args);
+ const warn = (...args)=>logImpl(1, ...args);
+ const error = (...args)=>logImpl(0, ...args);
+ const toss = sqlite3.util.toss;
+ const capi = sqlite3.capi;
+ const util = sqlite3.util;
+ const wasm = sqlite3.wasm;
+ const sqlite3_vfs = capi.sqlite3_vfs;
+ const sqlite3_file = capi.sqlite3_file;
+ const sqlite3_io_methods = capi.sqlite3_io_methods;
+ /**
+ Generic utilities for working with OPFS. This will get filled out
+ by the Promise setup and, on success, installed as sqlite3.opfs.
+
+ ACHTUNG: do not rely on these APIs in client code. They are
+ experimental and subject to change or removal as the
+ OPFS-specific sqlite3_vfs evolves.
+ */
+ const opfsUtil = Object.create(null);
+
+ /**
+ Returns true if _this_ thread has access to the OPFS APIs.
+ */
+ const thisThreadHasOPFS = ()=>{
+ return globalThis.FileSystemHandle &&
+ globalThis.FileSystemDirectoryHandle &&
+ globalThis.FileSystemFileHandle &&
+ globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle &&
+ navigator?.storage?.getDirectory;
+ };
+
+ /**
+ Not part of the public API. Solely for internal/development
+ use.
+ */
+ opfsUtil.metrics = {
+ dump: function(){
+ let k, n = 0, t = 0, w = 0;
+ for(k in state.opIds){
+ const m = metrics[k];
+ n += m.count;
+ t += m.time;
+ w += m.wait;
+ m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0;
+ m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0;
+ }
+ sqlite3.config.log(globalThis.location.href,
+ "metrics for",globalThis.location.href,":",metrics,
+ "\nTotal of",n,"op(s) for",t,
+ "ms (incl. "+w+" ms of waiting on the async side)");
+ sqlite3.config.log("Serialization metrics:",metrics.s11n);
+ W.postMessage({type:'opfs-async-metrics'});
+ },
+ reset: function(){
+ let k;
+ const r = (m)=>(m.count = m.time = m.wait = 0);
+ for(k in state.opIds){
+ r(metrics[k] = Object.create(null));
+ }
+ let s = metrics.s11n = Object.create(null);
+ s = s.serialize = Object.create(null);
+ s.count = s.time = 0;
+ s = metrics.s11n.deserialize = Object.create(null);
+ s.count = s.time = 0;
+ }
+ }/*metrics*/;
+ const opfsIoMethods = new sqlite3_io_methods();
+ const opfsVfs = new sqlite3_vfs()
+ .addOnDispose( ()=>opfsIoMethods.dispose());
+ let promiseWasRejected = undefined;
+ const promiseReject = (err)=>{
+ promiseWasRejected = true;
+ opfsVfs.dispose();
+ return promiseReject_(err);
+ };
+ const promiseResolve = ()=>{
+ promiseWasRejected = false;
+ return promiseResolve_(sqlite3);
+ };
+ const W =
+ new Worker(options.proxyUri);
+ setTimeout(()=>{
+ /* At attempt to work around a browser-specific quirk in which
+ the Worker load is failing in such a way that we neither
+ resolve nor reject it. This workaround gives that resolve/reject
+ a time limit and rejects if that timer expires. Discussion:
+ https://sqlite.org/forum/forumpost/a708c98dcb3ef */
+ if(undefined===promiseWasRejected){
+ promiseReject(
+ new Error("Timeout while waiting for OPFS async proxy worker.")
+ );
+ }
+ }, 4000);
+ W._originalOnError = W.onerror /* will be restored later */;
+ W.onerror = function(err){
+ // The error object doesn't contain any useful info when the
+ // failure is, e.g., that the remote script is 404.
+ error("Error initializing OPFS asyncer:",err);
+ promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons."));
+ };
+ const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/;
+ const dVfs = pDVfs
+ ? new sqlite3_vfs(pDVfs)
+ : null /* dVfs will be null when sqlite3 is built with
+ SQLITE_OS_OTHER. */;
+ opfsIoMethods.$iVersion = 1;
+ opfsVfs.$iVersion = 2/*yes, two*/;
+ opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
+ opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit
+ is undocumented/unspecified. */;
+ opfsVfs.$zName = wasm.allocCString("opfs");
+ // All C-side memory of opfsVfs is zeroed out, but just to be explicit:
+ opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
+ opfsVfs.addOnDispose(
+ '$zName', opfsVfs.$zName,
+ 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null)
+ );
+ /**
+ Pedantic sidebar about opfsVfs.ondispose: the entries in that array
+ are items to clean up when opfsVfs.dispose() is called, but in this
+ environment it will never be called. The VFS instance simply
+ hangs around until the WASM module instance is cleaned up. We
+ "could" _hypothetically_ clean it up by "importing" an
+ sqlite3_os_end() impl into the wasm build, but the shutdown order
+ of the wasm engine and the JS one are undefined so there is no
+ guaranty that the opfsVfs instance would be available in one
+ environment or the other when sqlite3_os_end() is called (_if_ it
+ gets called at all in a wasm build, which is undefined).
+ */
+ /**
+ State which we send to the async-api Worker or share with it.
+ This object must initially contain only cloneable or sharable
+ objects. After the worker's "inited" message arrives, other types
+ of data may be added to it.
+
+ For purposes of Atomics.wait() and Atomics.notify(), we use a
+ SharedArrayBuffer with one slot reserved for each of the API
+ proxy's methods. The sync side of the API uses Atomics.wait()
+ on the corresponding slot and the async side uses
+ Atomics.notify() on that slot.
+
+ The approach of using a single SAB to serialize comms for all
+ instances might(?) lead to deadlock situations in multi-db
+ cases. We should probably have one SAB here with a single slot
+ for locking a per-file initialization step and then allocate a
+ separate SAB like the above one for each file. That will
+ require a bit of acrobatics but should be feasible. The most
+ problematic part is that xOpen() would have to use
+ postMessage() to communicate its SharedArrayBuffer, and mixing
+ that approach with Atomics.wait/notify() gets a bit messy.
+ */
+ const state = Object.create(null);
+ state.verbose = options.verbose;
+ state.littleEndian = (()=>{
+ const buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 256, true /* ==>littleEndian */);
+ // Int16Array uses the platform's endianness.
+ return new Int16Array(buffer)[0] === 256;
+ })();
+ /**
+ asyncIdleWaitTime is how long (ms) to wait, in the async proxy,
+ for each Atomics.wait() when waiting on inbound VFS API calls.
+ We need to wake up periodically to give the thread a chance to
+ do other things. If this is too high (e.g. 500ms) then even two
+ workers/tabs can easily run into locking errors. Some multiple
+ of this value is also used for determining how long to wait on
+ lock contention to free up.
+ */
+ state.asyncIdleWaitTime = 150;
+
+ /**
+ Whether the async counterpart should log exceptions to
+ the serialization channel. That produces a great deal of
+ noise for seemingly innocuous things like xAccess() checks
+ for missing files, so this option may have one of 3 values:
+
+ 0 = no exception logging.
+
+ 1 = only log exceptions for "significant" ops like xOpen(),
+ xRead(), and xWrite().
+
+ 2 = log all exceptions.
+ */
+ state.asyncS11nExceptions = 1;
+ /* Size of file I/O buffer block. 64k = max sqlite3 page size, and
+ xRead/xWrite() will never deal in blocks larger than that. */
+ state.fileBufferSize = 1024 * 64;
+ state.sabS11nOffset = state.fileBufferSize;
+ /**
+ The size of the block in our SAB for serializing arguments and
+ result values. Needs to be large enough to hold serialized
+ values of any of the proxied APIs. Filenames are the largest
+ part but are limited to opfsVfs.$mxPathname bytes. We also
+ store exceptions there, so it needs to be long enough to hold
+ a reasonably long exception string.
+ */
+ state.sabS11nSize = opfsVfs.$mxPathname * 2;
+ /**
+ The SAB used for all data I/O between the synchronous and
+ async halves (file i/o and arg/result s11n).
+ */
+ state.sabIO = new SharedArrayBuffer(
+ state.fileBufferSize/* file i/o block */
+ + state.sabS11nSize/* argument/result serialization block */
+ );
+ state.opIds = Object.create(null);
+ const metrics = Object.create(null);
+ {
+ /* Indexes for use in our SharedArrayBuffer... */
+ let i = 0;
+ /* SAB slot used to communicate which operation is desired
+ between both workers. This worker writes to it and the other
+ listens for changes. */
+ state.opIds.whichOp = i++;
+ /* Slot for storing return values. This worker listens to that
+ slot and the other worker writes to it. */
+ state.opIds.rc = i++;
+ /* Each function gets an ID which this worker writes to
+ the whichOp slot. The async-api worker uses Atomic.wait()
+ on the whichOp slot to figure out which operation to run
+ next. */
+ state.opIds.xAccess = i++;
+ state.opIds.xClose = i++;
+ state.opIds.xDelete = i++;
+ state.opIds.xDeleteNoWait = i++;
+ state.opIds.xFileSize = i++;
+ state.opIds.xLock = i++;
+ state.opIds.xOpen = i++;
+ state.opIds.xRead = i++;
+ state.opIds.xSleep = i++;
+ state.opIds.xSync = i++;
+ state.opIds.xTruncate = i++;
+ state.opIds.xUnlock = i++;
+ state.opIds.xWrite = i++;
+ state.opIds.mkdir = i++;
+ state.opIds['opfs-async-metrics'] = i++;
+ state.opIds['opfs-async-shutdown'] = i++;
+ /* The retry slot is used by the async part for wait-and-retry
+ semantics. Though we could hypothetically use the xSleep slot
+ for that, doing so might lead to undesired side effects. */
+ state.opIds.retry = i++;
+ state.sabOP = new SharedArrayBuffer(
+ i * 4/* ==sizeof int32, noting that Atomics.wait() and friends
+ can only function on Int32Array views of an SAB. */);
+ opfsUtil.metrics.reset();
+ }
+ /**
+ SQLITE_xxx constants to export to the async worker
+ counterpart...
+ */
+ state.sq3Codes = Object.create(null);
+ [
+ 'SQLITE_ACCESS_EXISTS',
+ 'SQLITE_ACCESS_READWRITE',
+ 'SQLITE_BUSY',
+ 'SQLITE_CANTOPEN',
+ 'SQLITE_ERROR',
+ 'SQLITE_IOERR',
+ 'SQLITE_IOERR_ACCESS',
+ 'SQLITE_IOERR_CLOSE',
+ 'SQLITE_IOERR_DELETE',
+ 'SQLITE_IOERR_FSYNC',
+ 'SQLITE_IOERR_LOCK',
+ 'SQLITE_IOERR_READ',
+ 'SQLITE_IOERR_SHORT_READ',
+ 'SQLITE_IOERR_TRUNCATE',
+ 'SQLITE_IOERR_UNLOCK',
+ 'SQLITE_IOERR_WRITE',
+ 'SQLITE_LOCK_EXCLUSIVE',
+ 'SQLITE_LOCK_NONE',
+ 'SQLITE_LOCK_PENDING',
+ 'SQLITE_LOCK_RESERVED',
+ 'SQLITE_LOCK_SHARED',
+ 'SQLITE_LOCKED',
+ 'SQLITE_MISUSE',
+ 'SQLITE_NOTFOUND',
+ 'SQLITE_OPEN_CREATE',
+ 'SQLITE_OPEN_DELETEONCLOSE',
+ 'SQLITE_OPEN_MAIN_DB',
+ 'SQLITE_OPEN_READONLY'
+ ].forEach((k)=>{
+ if(undefined === (state.sq3Codes[k] = capi[k])){
+ toss("Maintenance required: not found:",k);
+ }
+ });
+ state.opfsFlags = Object.assign(Object.create(null),{
+ /**
+ Flag for use with xOpen(). URI flag "opfs-unlock-asap=1"
+ enables this. See defaultUnlockAsap, below.
+ */
+ OPFS_UNLOCK_ASAP: 0x01,
+ /**
+ Flag for use with xOpen(). URI flag "delete-before-open=1"
+ tells the VFS to delete the db file before attempting to open
+ it. This can be used, e.g., to replace a db which has been
+ corrupted (without forcing us to expose a delete/unlink()
+ function in the public API).
+
+ Failure to unlink the file is ignored but may lead to
+ downstream errors. An unlink can fail if, e.g., another tab
+ has the handle open.
+
+ It goes without saying that deleting a file out from under another
+ instance results in Undefined Behavior.
+ */
+ OPFS_UNLINK_BEFORE_OPEN: 0x02,
+ /**
+ If true, any async routine which implicitly acquires a sync
+ access handle (i.e. an OPFS lock) will release that lock at
+ the end of the call which acquires it. If false, such
+ "autolocks" are not released until the VFS is idle for some
+ brief amount of time.
+
+ The benefit of enabling this is much higher concurrency. The
+ down-side is much-reduced performance (as much as a 4x decrease
+ in speedtest1).
+ */
+ defaultUnlockAsap: false
+ });
+
+ /**
+ Runs the given operation (by name) in the async worker
+ counterpart, waits for its response, and returns the result
+ which the async worker writes to SAB[state.opIds.rc]. The
+ 2nd and subsequent arguments must be the aruguments for the
+ async op.
+ */
+ const opRun = (op,...args)=>{
+ const opNdx = state.opIds[op] || toss("Invalid op ID:",op);
+ state.s11n.serialize(...args);
+ Atomics.store(state.sabOPView, state.opIds.rc, -1);
+ Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx);
+ Atomics.notify(state.sabOPView, state.opIds.whichOp)
+ /* async thread will take over here */;
+ const t = performance.now();
+ while('not-equal'!==Atomics.wait(state.sabOPView, state.opIds.rc, -1)){
+ /*
+ The reason for this loop is buried in the details of a long
+ discussion at:
+
+ https://github.com/sqlite/sqlite-wasm/issues/12
+
+ Summary: in at least one browser flavor, under high loads,
+ the wait()/notify() pairings can get out of sync. Calling
+ wait() here until it returns 'not-equal' gets them back in
+ sync.
+ */
+ }
+ /* When the above wait() call returns 'not-equal', the async
+ half will have completed the operation and reported its results
+ in the state.opIds.rc slot of the SAB. */
+ const rc = Atomics.load(state.sabOPView, state.opIds.rc);
+ metrics[op].wait += performance.now() - t;
+ if(rc && state.asyncS11nExceptions){
+ const err = state.s11n.deserialize();
+ if(err) error(op+"() async error:",...err);
+ }
+ return rc;
+ };
+
+ /**
+ Not part of the public API. Only for test/development use.
+ */
+ opfsUtil.debug = {
+ asyncShutdown: ()=>{
+ warn("Shutting down OPFS async listener. The OPFS VFS will no longer work.");
+ opRun('opfs-async-shutdown');
+ },
+ asyncRestart: ()=>{
+ warn("Attempting to restart OPFS VFS async listener. Might work, might not.");
+ W.postMessage({type: 'opfs-async-restart'});
+ }
+ };
+
+ const initS11n = ()=>{
+ /**
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ ACHTUNG: this code is 100% duplicated in the other half of
+ this proxy! The documentation is maintained in the
+ "synchronous half".
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ This proxy de/serializes cross-thread function arguments and
+ output-pointer values via the state.sabIO SharedArrayBuffer,
+ using the region defined by (state.sabS11nOffset,
+ state.sabS11nOffset + state.sabS11nSize]. Only one dataset is
+ recorded at a time.
+
+ This is not a general-purpose format. It only supports the
+ range of operations, and data sizes, needed by the
+ sqlite3_vfs and sqlite3_io_methods operations. Serialized
+ data are transient and this serialization algorithm may
+ change at any time.
+
+ The data format can be succinctly summarized as:
+
+ Nt...Td...D
+
+ Where:
+
+ - N = number of entries (1 byte)
+
+ - t = type ID of first argument (1 byte)
+
+ - ...T = type IDs of the 2nd and subsequent arguments (1 byte
+ each).
+
+ - d = raw bytes of first argument (per-type size).
+
+ - ...D = raw bytes of the 2nd and subsequent arguments (per-type
+ size).
+
+ All types except strings have fixed sizes. Strings are stored
+ using their TextEncoder/TextDecoder representations. It would
+ arguably make more sense to store them as Int16Arrays of
+ their JS character values, but how best/fastest to get that
+ in and out of string form is an open point. Initial
+ experimentation with that approach did not gain us any speed.
+
+ Historical note: this impl was initially about 1% this size by
+ using using JSON.stringify/parse(), but using fit-to-purpose
+ serialization saves considerable runtime.
+ */
+ if(state.s11n) return state.s11n;
+ const textDecoder = new TextDecoder(),
+ textEncoder = new TextEncoder('utf-8'),
+ viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize),
+ viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize);
+ state.s11n = Object.create(null);
+ /* Only arguments and return values of these types may be
+ serialized. This covers the whole range of types needed by the
+ sqlite3_vfs API. */
+ const TypeIds = Object.create(null);
+ TypeIds.number = { id: 1, size: 8, getter: 'getFloat64', setter: 'setFloat64' };
+ TypeIds.bigint = { id: 2, size: 8, getter: 'getBigInt64', setter: 'setBigInt64' };
+ TypeIds.boolean = { id: 3, size: 4, getter: 'getInt32', setter: 'setInt32' };
+ TypeIds.string = { id: 4 };
+
+ const getTypeId = (v)=>(
+ TypeIds[typeof v]
+ || toss("Maintenance required: this value type cannot be serialized.",v)
+ );
+ const getTypeIdById = (tid)=>{
+ switch(tid){
+ case TypeIds.number.id: return TypeIds.number;
+ case TypeIds.bigint.id: return TypeIds.bigint;
+ case TypeIds.boolean.id: return TypeIds.boolean;
+ case TypeIds.string.id: return TypeIds.string;
+ default: toss("Invalid type ID:",tid);
+ }
+ };
+
+ /**
+ Returns an array of the deserialized state stored by the most
+ recent serialize() operation (from from this thread or the
+ counterpart thread), or null if the serialization buffer is
+ empty. If passed a truthy argument, the serialization buffer
+ is cleared after deserialization.
+ */
+ state.s11n.deserialize = function(clear=false){
+ ++metrics.s11n.deserialize.count;
+ const t = performance.now();
+ const argc = viewU8[0];
+ const rc = argc ? [] : null;
+ if(argc){
+ const typeIds = [];
+ let offset = 1, i, n, v;
+ for(i = 0; i < argc; ++i, ++offset){
+ typeIds.push(getTypeIdById(viewU8[offset]));
+ }
+ for(i = 0; i < argc; ++i){
+ const t = typeIds[i];
+ if(t.getter){
+ v = viewDV[t.getter](offset, state.littleEndian);
+ offset += t.size;
+ }else{/*String*/
+ n = viewDV.getInt32(offset, state.littleEndian);
+ offset += 4;
+ v = textDecoder.decode(viewU8.slice(offset, offset+n));
+ offset += n;
+ }
+ rc.push(v);
+ }
+ }
+ if(clear) viewU8[0] = 0;
+ //log("deserialize:",argc, rc);
+ metrics.s11n.deserialize.time += performance.now() - t;
+ return rc;
+ };
+
+ /**
+ Serializes all arguments to the shared buffer for consumption
+ by the counterpart thread.
+
+ This routine is only intended for serializing OPFS VFS
+ arguments and (in at least one special case) result values,
+ and the buffer is sized to be able to comfortably handle
+ those.
+
+ If passed no arguments then it zeroes out the serialization
+ state.
+ */
+ state.s11n.serialize = function(...args){
+ const t = performance.now();
+ ++metrics.s11n.serialize.count;
+ if(args.length){
+ //log("serialize():",args);
+ const typeIds = [];
+ let i = 0, offset = 1;
+ viewU8[0] = args.length & 0xff /* header = # of args */;
+ for(; i < args.length; ++i, ++offset){
+ /* Write the TypeIds.id value into the next args.length
+ bytes. */
+ typeIds.push(getTypeId(args[i]));
+ viewU8[offset] = typeIds[i].id;
+ }
+ for(i = 0; i < args.length; ++i) {
+ /* Deserialize the following bytes based on their
+ corresponding TypeIds.id from the header. */
+ const t = typeIds[i];
+ if(t.setter){
+ viewDV[t.setter](offset, args[i], state.littleEndian);
+ offset += t.size;
+ }else{/*String*/
+ const s = textEncoder.encode(args[i]);
+ viewDV.setInt32(offset, s.byteLength, state.littleEndian);
+ offset += 4;
+ viewU8.set(s, offset);
+ offset += s.byteLength;
+ }
+ }
+ //log("serialize() result:",viewU8.slice(0,offset));
+ }else{
+ viewU8[0] = 0;
+ }
+ metrics.s11n.serialize.time += performance.now() - t;
+ };
+ return state.s11n;
+ }/*initS11n()*/;
+
+ /**
+ Generates a random ASCII string len characters long, intended for
+ use as a temporary file name.
+ */
+ const randomFilename = function f(len=16){
+ if(!f._chars){
+ f._chars = "abcdefghijklmnopqrstuvwxyz"+
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
+ "012346789";
+ f._n = f._chars.length;
+ }
+ const a = [];
+ let i = 0;
+ for( ; i < len; ++i){
+ const ndx = Math.random() * (f._n * 64) % f._n | 0;
+ a[i] = f._chars[ndx];
+ }
+ return a.join("");
+ /*
+ An alternative impl. with an unpredictable length
+ but much simpler:
+
+ Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36)
+ */
+ };
+
+ /**
+ Map of sqlite3_file pointers to objects constructed by xOpen().
+ */
+ const __openFiles = Object.create(null);
+
+ const opTimer = Object.create(null);
+ opTimer.op = undefined;
+ opTimer.start = undefined;
+ const mTimeStart = (op)=>{
+ opTimer.start = performance.now();
+ opTimer.op = op;
+ ++metrics[op].count;
+ };
+ const mTimeEnd = ()=>(
+ metrics[opTimer.op].time += performance.now() - opTimer.start
+ );
+
+ /**
+ Impls for the sqlite3_io_methods methods. Maintenance reminder:
+ members are in alphabetical order to simplify finding them.
+ */
+ const ioSyncWrappers = {
+ xCheckReservedLock: function(pFile,pOut){
+ /**
+ As of late 2022, only a single lock can be held on an OPFS
+ file. We have no way of checking whether any _other_ db
+ connection has a lock except by trying to obtain and (on
+ success) release a sync-handle for it, but doing so would
+ involve an inherent race condition. For the time being,
+ pending a better solution, we simply report whether the
+ given pFile is open.
+
+ Update 2024-06-12: based on forum discussions, this
+ function now always sets pOut to 0 (false):
+
+ https://sqlite.org/forum/forumpost/a2f573b00cda1372
+ */
+ wasm.poke(pOut, 0, 'i32');
+ return 0;
+ },
+ xClose: function(pFile){
+ mTimeStart('xClose');
+ let rc = 0;
+ const f = __openFiles[pFile];
+ if(f){
+ delete __openFiles[pFile];
+ rc = opRun('xClose', pFile);
+ if(f.sq3File) f.sq3File.dispose();
+ }
+ mTimeEnd();
+ return rc;
+ },
+ xDeviceCharacteristics: function(pFile){
+ return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
+ },
+ xFileControl: function(pFile, opId, pArg){
+ /*mTimeStart('xFileControl');
+ mTimeEnd();*/
+ return capi.SQLITE_NOTFOUND;
+ },
+ xFileSize: function(pFile,pSz64){
+ mTimeStart('xFileSize');
+ let rc = opRun('xFileSize', pFile);
+ if(0==rc){
+ try {
+ const sz = state.s11n.deserialize()[0];
+ wasm.poke(pSz64, sz, 'i64');
+ }catch(e){
+ error("Unexpected error reading xFileSize() result:",e);
+ rc = state.sq3Codes.SQLITE_IOERR;
+ }
+ }
+ mTimeEnd();
+ return rc;
+ },
+ xLock: function(pFile,lockType){
+ mTimeStart('xLock');
+ const f = __openFiles[pFile];
+ let rc = 0;
+ /* All OPFS locks are exclusive locks. If xLock() has
+ previously succeeded, do nothing except record the lock
+ type. If no lock is active, have the async counterpart
+ lock the file. */
+ if( !f.lockType ) {
+ rc = opRun('xLock', pFile, lockType);
+ if( 0===rc ) f.lockType = lockType;
+ }else{
+ f.lockType = lockType;
+ }
+ mTimeEnd();
+ return rc;
+ },
+ xRead: function(pFile,pDest,n,offset64){
+ mTimeStart('xRead');
+ const f = __openFiles[pFile];
+ let rc;
+ try {
+ rc = opRun('xRead',pFile, n, Number(offset64));
+ if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){
+ /**
+ Results get written to the SharedArrayBuffer f.sabView.
+ Because the heap is _not_ a SharedArrayBuffer, we have
+ to copy the results. TypedArray.set() seems to be the
+ fastest way to copy this. */
+ wasm.heap8u().set(f.sabView.subarray(0, n), pDest);
+ }
+ }catch(e){
+ error("xRead(",arguments,") failed:",e,f);
+ rc = capi.SQLITE_IOERR_READ;
+ }
+ mTimeEnd();
+ return rc;
+ },
+ xSync: function(pFile,flags){
+ mTimeStart('xSync');
+ ++metrics.xSync.count;
+ const rc = opRun('xSync', pFile, flags);
+ mTimeEnd();
+ return rc;
+ },
+ xTruncate: function(pFile,sz64){
+ mTimeStart('xTruncate');
+ const rc = opRun('xTruncate', pFile, Number(sz64));
+ mTimeEnd();
+ return rc;
+ },
+ xUnlock: function(pFile,lockType){
+ mTimeStart('xUnlock');
+ const f = __openFiles[pFile];
+ let rc = 0;
+ if( capi.SQLITE_LOCK_NONE === lockType
+ && f.lockType ){
+ rc = opRun('xUnlock', pFile, lockType);
+ }
+ if( 0===rc ) f.lockType = lockType;
+ mTimeEnd();
+ return rc;
+ },
+ xWrite: function(pFile,pSrc,n,offset64){
+ mTimeStart('xWrite');
+ const f = __openFiles[pFile];
+ let rc;
+ try {
+ f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc+n));
+ rc = opRun('xWrite', pFile, n, Number(offset64));
+ }catch(e){
+ error("xWrite(",arguments,") failed:",e,f);
+ rc = capi.SQLITE_IOERR_WRITE;
+ }
+ mTimeEnd();
+ return rc;
+ }
+ }/*ioSyncWrappers*/;
+
+ /**
+ Impls for the sqlite3_vfs methods. Maintenance reminder: members
+ are in alphabetical order to simplify finding them.
+ */
+ const vfsSyncWrappers = {
+ xAccess: function(pVfs,zName,flags,pOut){
+ mTimeStart('xAccess');
+ const rc = opRun('xAccess', wasm.cstrToJs(zName));
+ wasm.poke( pOut, (rc ? 0 : 1), 'i32' );
+ mTimeEnd();
+ return 0;
+ },
+ xCurrentTime: function(pVfs,pOut){
+ /* If it turns out that we need to adjust for timezone, see:
+ https://stackoverflow.com/a/11760121/1458521 */
+ wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000),
+ 'double');
+ return 0;
+ },
+ xCurrentTimeInt64: function(pVfs,pOut){
+ wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(),
+ 'i64');
+ return 0;
+ },
+ xDelete: function(pVfs, zName, doSyncDir){
+ mTimeStart('xDelete');
+ const rc = opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false);
+ mTimeEnd();
+ return rc;
+ },
+ xFullPathname: function(pVfs,zName,nOut,pOut){
+ /* Until/unless we have some notion of "current dir"
+ in OPFS, simply copy zName to pOut... */
+ const i = wasm.cstrncpy(pOut, zName, nOut);
+ return i<nOut ? 0 : capi.SQLITE_CANTOPEN
+ /*CANTOPEN is required by the docs but SQLITE_RANGE would be a closer match*/;
+ },
+ xGetLastError: function(pVfs,nOut,pOut){
+ /* TODO: store exception.message values from the async
+ partner in a dedicated SharedArrayBuffer, noting that we'd have
+ to encode them... TextEncoder can do that for us. */
+ warn("OPFS xGetLastError() has nothing sensible to return.");
+ return 0;
+ },
+ //xSleep is optionally defined below
+ xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
+ mTimeStart('xOpen');
+ let opfsFlags = 0;
+ if(0===zName){
+ zName = randomFilename();
+ }else if(wasm.isPtr(zName)){
+ if(capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)){
+ /* -----------------------^^^^^ MUST pass the untranslated
+ C-string here. */
+ opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP;
+ }
+ if(capi.sqlite3_uri_boolean(zName, "delete-before-open", 0)){
+ opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN;
+ }
+ zName = wasm.cstrToJs(zName);
+ //warn("xOpen zName =",zName, "opfsFlags =",opfsFlags);
+ }
+ const fh = Object.create(null);
+ fh.fid = pFile;
+ fh.filename = zName;
+ fh.sab = new SharedArrayBuffer(state.fileBufferSize);
+ fh.flags = flags;
+ fh.readOnly = !(sqlite3.SQLITE_OPEN_CREATE & flags)
+ && !!(flags & capi.SQLITE_OPEN_READONLY);
+ const rc = opRun('xOpen', pFile, zName, flags, opfsFlags);
+ if(!rc){
+ /* Recall that sqlite3_vfs::xClose() will be called, even on
+ error, unless pFile->pMethods is NULL. */
+ if(fh.readOnly){
+ wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32');
+ }
+ __openFiles[pFile] = fh;
+ fh.sabView = state.sabFileBufView;
+ fh.sq3File = new sqlite3_file(pFile);
+ fh.sq3File.$pMethods = opfsIoMethods.pointer;
+ fh.lockType = capi.SQLITE_LOCK_NONE;
+ }
+ mTimeEnd();
+ return rc;
+ }/*xOpen()*/
+ }/*vfsSyncWrappers*/;
+
+ if(dVfs){
+ opfsVfs.$xRandomness = dVfs.$xRandomness;
+ opfsVfs.$xSleep = dVfs.$xSleep;
+ }
+ if(!opfsVfs.$xRandomness){
+ /* If the default VFS has no xRandomness(), add a basic JS impl... */
+ vfsSyncWrappers.xRandomness = function(pVfs, nOut, pOut){
+ const heap = wasm.heap8u();
+ let i = 0;
+ for(; i < nOut; ++i) heap[pOut + i] = (Math.random()*255000) & 0xFF;
+ return i;
+ };
+ }
+ if(!opfsVfs.$xSleep){
+ /* If we can inherit an xSleep() impl from the default VFS then
+ assume it's sane and use it, otherwise install a JS-based
+ one. */
+ vfsSyncWrappers.xSleep = function(pVfs,ms){
+ Atomics.wait(state.sabOPView, state.opIds.xSleep, 0, ms);
+ return 0;
+ };
+ }
+
+ /**
+ Expects an OPFS file path. It gets resolved, such that ".."
+ components are properly expanded, and returned. If the 2nd arg
+ is true, the result is returned as an array of path elements,
+ else an absolute path string is returned.
+ */
+ opfsUtil.getResolvedPath = function(filename,splitIt){
+ const p = new URL(filename, "file://irrelevant").pathname;
+ return splitIt ? p.split('/').filter((v)=>!!v) : p;
+ };
+
+ /**
+ Takes the absolute path to a filesystem element. Returns an
+ array of [handleOfContainingDir, filename]. If the 2nd argument
+ is truthy then each directory element leading to the file is
+ created along the way. Throws if any creation or resolution
+ fails.
+ */
+ opfsUtil.getDirForFilename = async function f(absFilename, createDirs = false){
+ const path = opfsUtil.getResolvedPath(absFilename, true);
+ const filename = path.pop();
+ let dh = opfsUtil.rootDirectory;
+ for(const dirName of path){
+ if(dirName){
+ dh = await dh.getDirectoryHandle(dirName, {create: !!createDirs});
+ }
+ }
+ return [dh, filename];
+ };
+
+ /**
+ Creates the given directory name, recursively, in
+ the OPFS filesystem. Returns true if it succeeds or the
+ directory already exists, else false.
+ */
+ opfsUtil.mkdir = async function(absDirName){
+ try {
+ await opfsUtil.getDirForFilename(absDirName+"/filepart", true);
+ return true;
+ }catch(e){
+ //sqlite3.config.warn("mkdir(",absDirName,") failed:",e);
+ return false;
+ }
+ };
+ /**
+ Checks whether the given OPFS filesystem entry exists,
+ returning true if it does, false if it doesn't or if an
+ exception is intercepted while trying to make the
+ determination.
+ */
+ opfsUtil.entryExists = async function(fsEntryName){
+ try {
+ const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName);
+ await dh.getFileHandle(fn);
+ return true;
+ }catch(e){
+ return false;
+ }
+ };
+
+ /**
+ Generates a random ASCII string, intended for use as a
+ temporary file name. Its argument is the length of the string,
+ defaulting to 16.
+ */
+ opfsUtil.randomFilename = randomFilename;
+
+ /**
+ Returns a promise which resolves to an object which represents
+ all files and directories in the OPFS tree. The top-most object
+ has two properties: `dirs` is an array of directory entries
+ (described below) and `files` is a list of file names for all
+ files in that directory.
+
+ Traversal starts at sqlite3.opfs.rootDirectory.
+
+ Each `dirs` entry is an object in this form:
+
+ ```
+ { name: directoryName,
+ dirs: [...subdirs],
+ files: [...file names]
+ }
+ ```
+
+ The `files` and `subdirs` entries are always set but may be
+ empty arrays.
+
+ The returned object has the same structure but its `name` is
+ an empty string. All returned objects are created with
+ Object.create(null), so have no prototype.
+
+ Design note: the entries do not contain more information,
+ e.g. file sizes, because getting such info is not only
+ expensive but is subject to locking-related errors.
+ */
+ opfsUtil.treeList = async function(){
+ const doDir = async function callee(dirHandle,tgt){
+ tgt.name = dirHandle.name;
+ tgt.dirs = [];
+ tgt.files = [];
+ for await (const handle of dirHandle.values()){
+ if('directory' === handle.kind){
+ const subDir = Object.create(null);
+ tgt.dirs.push(subDir);
+ await callee(handle, subDir);
+ }else{
+ tgt.files.push(handle.name);
+ }
+ }
+ };
+ const root = Object.create(null);
+ await doDir(opfsUtil.rootDirectory, root);
+ return root;
+ };
+
+ /**
+ Irrevocably deletes _all_ files in the current origin's OPFS.
+ Obviously, this must be used with great caution. It may throw
+ an exception if removal of anything fails (e.g. a file is
+ locked), but the precise conditions under which the underlying
+ APIs will throw are not documented (so we cannot tell you what
+ they are).
+ */
+ opfsUtil.rmfr = async function(){
+ const dir = opfsUtil.rootDirectory, opt = {recurse: true};
+ for await (const handle of dir.values()){
+ dir.removeEntry(handle.name, opt);
+ }
+ };
+
+ /**
+ Deletes the given OPFS filesystem entry. As this environment
+ has no notion of "current directory", the given name must be an
+ absolute path. If the 2nd argument is truthy, deletion is
+ recursive (use with caution!).
+
+ The returned Promise resolves to true if the deletion was
+ successful, else false (but...). The OPFS API reports the
+ reason for the failure only in human-readable form, not
+ exceptions which can be type-checked to determine the
+ failure. Because of that...
+
+ If the final argument is truthy then this function will
+ propagate any exception on error, rather than returning false.
+ */
+ opfsUtil.unlink = async function(fsEntryName, recursive = false,
+ throwOnError = false){
+ try {
+ const [hDir, filenamePart] =
+ await opfsUtil.getDirForFilename(fsEntryName, false);
+ await hDir.removeEntry(filenamePart, {recursive});
+ return true;
+ }catch(e){
+ if(throwOnError){
+ throw new Error("unlink(",arguments[0],") failed: "+e.message,{
+ cause: e
+ });
+ }
+ return false;
+ }
+ };
+
+ /**
+ Traverses the OPFS filesystem, calling a callback for each
+ entry. The argument may be either a callback function or an
+ options object with any of the following properties:
+
+ - `callback`: function which gets called for each filesystem
+ entry. It gets passed 3 arguments: 1) the
+ FileSystemFileHandle or FileSystemDirectoryHandle of each
+ entry (noting that both are instanceof FileSystemHandle). 2)
+ the FileSystemDirectoryHandle of the parent directory. 3) the
+ current depth level, with 0 being at the top of the tree
+ relative to the starting directory. If the callback returns a
+ literal false, as opposed to any other falsy value, traversal
+ stops without an error. Any exceptions it throws are
+ propagated. Results are undefined if the callback manipulate
+ the filesystem (e.g. removing or adding entries) because the
+ how OPFS iterators behave in the face of such changes is
+ undocumented.
+
+ - `recursive` [bool=true]: specifies whether to recurse into
+ subdirectories or not. Whether recursion is depth-first or
+ breadth-first is unspecified!
+
+ - `directory` [FileSystemDirectoryEntry=sqlite3.opfs.rootDirectory]
+ specifies the starting directory.
+
+ If this function is passed a function, it is assumed to be the
+ callback.
+
+ Returns a promise because it has to (by virtue of being async)
+ but that promise has no specific meaning: the traversal it
+ performs is synchronous. The promise must be used to catch any
+ exceptions propagated by the callback, however.
+ */
+ opfsUtil.traverse = async function(opt){
+ const defaultOpt = {
+ recursive: true,
+ directory: opfsUtil.rootDirectory
+ };
+ if('function'===typeof opt){
+ opt = {callback:opt};
+ }
+ opt = Object.assign(defaultOpt, opt||{});
+ const doDir = async function callee(dirHandle, depth){
+ for await (const handle of dirHandle.values()){
+ if(false === opt.callback(handle, dirHandle, depth)) return false;
+ else if(opt.recursive && 'directory' === handle.kind){
+ if(false === await callee(handle, depth + 1)) break;
+ }
+ }
+ };
+ doDir(opt.directory, 0);
+ };
+
+ /**
+ impl of importDb() when it's given a function as its second
+ argument.
+ */
+ const importDbChunked = async function(filename, callback){
+ const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true);
+ const hFile = await hDir.getFileHandle(fnamePart, {create:true});
+ let sah = await hFile.createSyncAccessHandle();
+ let nWrote = 0, chunk, checkedHeader = false, err = false;
+ try{
+ sah.truncate(0);
+ while( undefined !== (chunk = await callback()) ){
+ if(chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk);
+ if( 0===nWrote && chunk.byteLength>=15 ){
+ util.affirmDbHeader(chunk);
+ checkedHeader = true;
+ }
+ sah.write(chunk, {at: nWrote});
+ nWrote += chunk.byteLength;
+ }
+ if( nWrote < 512 || 0!==nWrote % 512 ){
+ toss("Input size",nWrote,"is not correct for an SQLite database.");
+ }
+ if( !checkedHeader ){
+ const header = new Uint8Array(20);
+ sah.read( header, {at: 0} );
+ util.affirmDbHeader( header );
+ }
+ sah.write(new Uint8Array([1,1]), {at: 18}/*force db out of WAL mode*/);
+ return nWrote;
+ }catch(e){
+ await sah.close();
+ sah = undefined;
+ await hDir.removeEntry( fnamePart ).catch(()=>{});
+ throw e;
+ }finally {
+ if( sah ) await sah.close();
+ }
+ };
+
+ /**
+ Asynchronously imports the given bytes (a byte array or
+ ArrayBuffer) into the given database file.
+
+ Results are undefined if the given db name refers to an opened
+ db.
+
+ If passed a function for its second argument, its behaviour
+ changes: imports its data in chunks fed to it by the given
+ callback function. It calls the callback (which may be async)
+ repeatedly, expecting either a Uint8Array or ArrayBuffer (to
+ denote new input) or undefined (to denote EOF). For so long as
+ the callback continues to return non-undefined, it will append
+ incoming data to the given VFS-hosted database file. When
+ called this way, the resolved value of the returned Promise is
+ the number of bytes written to the target file.
+
+ It very specifically requires the input to be an SQLite3
+ database and throws if that's not the case. It does so in
+ order to prevent this function from taking on a larger scope
+ than it is specifically intended to. i.e. we do not want it to
+ become a convenience for importing arbitrary files into OPFS.
+
+ This routine rewrites the database header bytes in the output
+ file (not the input array) to force disabling of WAL mode.
+
+ On error this throws and the state of the input file is
+ undefined (it depends on where the exception was triggered).
+
+ On success, resolves to the number of bytes written.
+ */
+ opfsUtil.importDb = async function(filename, bytes){
+ if( bytes instanceof Function ){
+ return importDbChunked(filename, bytes);
+ }
+ if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
+ util.affirmIsDb(bytes);
+ const n = bytes.byteLength;
+ const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true);
+ let sah, err, nWrote = 0;
+ try {
+ const hFile = await hDir.getFileHandle(fnamePart, {create:true});
+ sah = await hFile.createSyncAccessHandle();
+ sah.truncate(0);
+ nWrote = sah.write(bytes, {at: 0});
+ if(nWrote != n){
+ toss("Expected to write "+n+" bytes but wrote "+nWrote+".");
+ }
+ sah.write(new Uint8Array([1,1]), {at: 18}) /* force db out of WAL mode */;
+ return nWrote;
+ }catch(e){
+ if( sah ){ await sah.close(); sah = undefined; }
+ await hDir.removeEntry( fnamePart ).catch(()=>{});
+ throw e;
+ }finally{
+ if( sah ) await sah.close();
+ }
+ };
+
+ if(sqlite3.oo1){
+ const OpfsDb = function(...args){
+ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
+ opt.vfs = opfsVfs.$zName;
+ sqlite3.oo1.DB.dbCtorHelper.call(this, opt);
+ };
+ OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
+ sqlite3.oo1.OpfsDb = OpfsDb;
+ OpfsDb.importDb = opfsUtil.importDb;
+ sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback(
+ opfsVfs.pointer,
+ function(oo1Db, sqlite3){
+ /* Set a relatively high default busy-timeout handler to
+ help OPFS dbs deal with multi-tab/multi-worker
+ contention. */
+ sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000);
+ }
+ );
+ }/*extend sqlite3.oo1*/
+
+ const sanityCheck = function(){
+ const scope = wasm.scopedAllocPush();
+ const sq3File = new sqlite3_file();
+ try{
+ const fid = sq3File.pointer;
+ const openFlags = capi.SQLITE_OPEN_CREATE
+ | capi.SQLITE_OPEN_READWRITE
+ //| capi.SQLITE_OPEN_DELETEONCLOSE
+ | capi.SQLITE_OPEN_MAIN_DB;
+ const pOut = wasm.scopedAlloc(8);
+ const dbFile = "/sanity/check/file"+randomFilename(8);
+ const zDbFile = wasm.scopedAllocCString(dbFile);
+ let rc;
+ state.s11n.serialize("This is ä string.");
+ rc = state.s11n.deserialize();
+ log("deserialize() says:",rc);
+ if("This is ä string."!==rc[0]) toss("String d13n error.");
+ vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
+ rc = wasm.peek(pOut,'i32');
+ log("xAccess(",dbFile,") exists ?=",rc);
+ rc = vfsSyncWrappers.xOpen(opfsVfs.pointer, zDbFile,
+ fid, openFlags, pOut);
+ log("open rc =",rc,"state.sabOPView[xOpen] =",
+ state.sabOPView[state.opIds.xOpen]);
+ if(0!==rc){
+ error("open failed with code",rc);
+ return;
+ }
+ vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
+ rc = wasm.peek(pOut,'i32');
+ if(!rc) toss("xAccess() failed to detect file.");
+ rc = ioSyncWrappers.xSync(sq3File.pointer, 0);
+ if(rc) toss('sync failed w/ rc',rc);
+ rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024);
+ if(rc) toss('truncate failed w/ rc',rc);
+ wasm.poke(pOut,0,'i64');
+ rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut);
+ if(rc) toss('xFileSize failed w/ rc',rc);
+ log("xFileSize says:",wasm.peek(pOut, 'i64'));
+ rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1);
+ if(rc) toss("xWrite() failed!");
+ const readBuf = wasm.scopedAlloc(16);
+ rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2);
+ wasm.poke(readBuf+6,0);
+ let jRead = wasm.cstrToJs(readBuf);
+ log("xRead() got:",jRead);
+ if("sanity"!==jRead) toss("Unexpected xRead() value.");
+ if(vfsSyncWrappers.xSleep){
+ log("xSleep()ing before close()ing...");
+ vfsSyncWrappers.xSleep(opfsVfs.pointer,2000);
+ log("waking up from xSleep()");
+ }
+ rc = ioSyncWrappers.xClose(fid);
+ log("xClose rc =",rc,"sabOPView =",state.sabOPView);
+ log("Deleting file:",dbFile);
+ vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234);
+ vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
+ rc = wasm.peek(pOut,'i32');
+ if(rc) toss("Expecting 0 from xAccess(",dbFile,") after xDelete().");
+ warn("End of OPFS sanity checks.");
+ }finally{
+ sq3File.dispose();
+ wasm.scopedAllocPop(scope);
+ }
+ }/*sanityCheck()*/;
+
+ W.onmessage = function({data}){
+ //log("Worker.onmessage:",data);
+ switch(data.type){
+ case 'opfs-unavailable':
+ /* Async proxy has determined that OPFS is unavailable. There's
+ nothing more for us to do here. */
+ promiseReject(new Error(data.payload.join(' ')));
+ break;
+ case 'opfs-async-loaded':
+ /* Arrives as soon as the asyc proxy finishes loading.
+ Pass our config and shared state on to the async
+ worker. */
+ W.postMessage({type: 'opfs-async-init',args: state});
+ break;
+ case 'opfs-async-inited': {
+ /* Indicates that the async partner has received the 'init'
+ and has finished initializing, so the real work can
+ begin... */
+ if(true===promiseWasRejected){
+ break /* promise was already rejected via timer */;
+ }
+ try {
+ sqlite3.vfs.installVfs({
+ io: {struct: opfsIoMethods, methods: ioSyncWrappers},
+ vfs: {struct: opfsVfs, methods: vfsSyncWrappers}
+ });
+ state.sabOPView = new Int32Array(state.sabOP);
+ state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize);
+ state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize);
+ initS11n();
+ if(options.sanityChecks){
+ warn("Running sanity checks because of opfs-sanity-check URL arg...");
+ sanityCheck();
+ }
+ if(thisThreadHasOPFS()){
+ navigator.storage.getDirectory().then((d)=>{
+ W.onerror = W._originalOnError;
+ delete W._originalOnError;
+ sqlite3.opfs = opfsUtil;
+ opfsUtil.rootDirectory = d;
+ log("End of OPFS sqlite3_vfs setup.", opfsVfs);
+ promiseResolve();
+ }).catch(promiseReject);
+ }else{
+ promiseResolve();
+ }
+ }catch(e){
+ error(e);
+ promiseReject(e);
+ }
+ break;
+ }
+ default: {
+ const errMsg = (
+ "Unexpected message from the OPFS async worker: " +
+ JSON.stringify(data)
+ );
+ error(errMsg);
+ promiseReject(new Error(errMsg));
+ break;
+ }
+ }/*switch(data.type)*/
+ }/*W.onmessage()*/;
+ })/*thePromise*/;
+ return thePromise;
+}/*installOpfsVfs()*/;
+installOpfsVfs.defaultProxyUri =
+ "sqlite3-opfs-async-proxy.js";
+globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
+ try{
+ let proxyJs = installOpfsVfs.defaultProxyUri;
+ if(sqlite3.scriptInfo.sqlite3Dir){
+ installOpfsVfs.defaultProxyUri =
+ sqlite3.scriptInfo.sqlite3Dir + proxyJs;
+ //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri);
+ }
+ return installOpfsVfs().catch((e)=>{
+ sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e.message);
+ });
+ }catch(e){
+ sqlite3.config.error("installOpfsVfs() exception:",e);
+ return Promise.reject(e);
+ }
+});
+}/*sqlite3ApiBootstrap.initializers.push()*/);
+/* END FILE: api/sqlite3-vfs-opfs.c-pp.js */
+/* BEGIN FILE: api/sqlite3-vfs-opfs-sahpool.c-pp.js */
+/*
+ 2023-07-14
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file holds a sqlite3_vfs backed by OPFS storage which uses a
+ different implementation strategy than the "opfs" VFS. This one is a
+ port of Roy Hashimoto's OPFS SyncAccessHandle pool:
+
+ https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/AccessHandlePoolVFS.js
+
+ As described at:
+
+ https://github.com/rhashimoto/wa-sqlite/discussions/67
+
+ with Roy's explicit permission to permit us to port his to our
+ infrastructure rather than having to clean-room reverse-engineer it:
+
+ https://sqlite.org/forum/forumpost/e140d84e71
+
+ Primary differences from the "opfs" VFS include:
+
+ - This one avoids the need for a sub-worker to synchronize
+ communication between the synchronous C API and the
+ only-partly-synchronous OPFS API.
+
+ - It does so by opening a fixed number of OPFS files at
+ library-level initialization time, obtaining SyncAccessHandles to
+ each, and manipulating those handles via the synchronous sqlite3_vfs
+ interface. If it cannot open them (e.g. they are already opened by
+ another tab) then the VFS will not be installed.
+
+ - Because of that, this one lacks all library-level concurrency
+ support.
+
+ - Also because of that, it does not require the SharedArrayBuffer,
+ so can function without the COOP/COEP HTTP response headers.
+
+ - It can hypothetically support Safari 16.4+, whereas the "opfs" VFS
+ requires v17 due to a subworker/storage bug in 16.x which makes it
+ incompatible with that VFS.
+
+ - This VFS requires the "semi-fully-sync" FileSystemSyncAccessHandle
+ (hereafter "SAH") APIs released with Chrome v108 (and all other
+ major browsers released since March 2023). If that API is not
+ detected, the VFS is not registered.
+*/
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ 'use strict';
+ const toss = sqlite3.util.toss;
+ const toss3 = sqlite3.util.toss3;
+ const initPromises = Object.create(null) /* cache of (name:result) of VFS init results */;
+ const capi = sqlite3.capi;
+ const util = sqlite3.util;
+ const wasm = sqlite3.wasm;
+ // Config opts for the VFS...
+ const SECTOR_SIZE = 4096;
+ const HEADER_MAX_PATH_SIZE = 512;
+ const HEADER_FLAGS_SIZE = 4;
+ const HEADER_DIGEST_SIZE = 8;
+ const HEADER_CORPUS_SIZE = HEADER_MAX_PATH_SIZE + HEADER_FLAGS_SIZE;
+ const HEADER_OFFSET_FLAGS = HEADER_MAX_PATH_SIZE;
+ const HEADER_OFFSET_DIGEST = HEADER_CORPUS_SIZE;
+ const HEADER_OFFSET_DATA = SECTOR_SIZE;
+ /* Bitmask of file types which may persist across sessions.
+ SQLITE_OPEN_xyz types not listed here may be inadvertently
+ left in OPFS but are treated as transient by this VFS and
+ they will be cleaned up during VFS init. */
+ const PERSISTENT_FILE_TYPES =
+ capi.SQLITE_OPEN_MAIN_DB |
+ capi.SQLITE_OPEN_MAIN_JOURNAL |
+ capi.SQLITE_OPEN_SUPER_JOURNAL |
+ capi.SQLITE_OPEN_WAL;
+
+ /** Subdirectory of the VFS's space where "opaque" (randomly-named)
+ files are stored. Changing this effectively invalidates the data
+ stored under older names (orphaning it), so don't do that. */
+ const OPAQUE_DIR_NAME = ".opaque";
+
+ /**
+ Returns short a string of random alphanumeric characters
+ suitable for use as a random filename.
+ */
+ const getRandomName = ()=>Math.random().toString(36).slice(2);
+
+ const textDecoder = new TextDecoder();
+ const textEncoder = new TextEncoder();
+
+ const optionDefaults = Object.assign(Object.create(null),{
+ name: 'opfs-sahpool',
+ directory: undefined /* derived from .name */,
+ initialCapacity: 6,
+ clearOnInit: false,
+ /* Logging verbosity 3+ == everything, 2 == warnings+errors, 1 ==
+ errors only. */
+ verbosity: 2,
+ forceReinitIfPreviouslyFailed: false
+ });
+
+ /** Logging routines, from most to least serious. */
+ const loggers = [
+ sqlite3.config.error,
+ sqlite3.config.warn,
+ sqlite3.config.log
+ ];
+ const log = sqlite3.config.log;
+ const warn = sqlite3.config.warn;
+ const error = sqlite3.config.error;
+
+ /* Maps (sqlite3_vfs*) to OpfsSAHPool instances */
+ const __mapVfsToPool = new Map();
+ const getPoolForVfs = (pVfs)=>__mapVfsToPool.get(pVfs);
+ const setPoolForVfs = (pVfs,pool)=>{
+ if(pool) __mapVfsToPool.set(pVfs, pool);
+ else __mapVfsToPool.delete(pVfs);
+ };
+ /* Maps (sqlite3_file*) to OpfsSAHPool instances */
+ const __mapSqlite3File = new Map();
+ const getPoolForPFile = (pFile)=>__mapSqlite3File.get(pFile);
+ const setPoolForPFile = (pFile,pool)=>{
+ if(pool) __mapSqlite3File.set(pFile, pool);
+ else __mapSqlite3File.delete(pFile);
+ };
+
+ /**
+ Impls for the sqlite3_io_methods methods. Maintenance reminder:
+ members are in alphabetical order to simplify finding them.
+ */
+ const ioMethods = {
+ xCheckReservedLock: function(pFile,pOut){
+ const pool = getPoolForPFile(pFile);
+ pool.log('xCheckReservedLock');
+ pool.storeErr();
+ wasm.poke32(pOut, 1);
+ return 0;
+ },
+ xClose: function(pFile){
+ const pool = getPoolForPFile(pFile);
+ pool.storeErr();
+ const file = pool.getOFileForS3File(pFile);
+ if(file) {
+ try{
+ pool.log(`xClose ${file.path}`);
+ pool.mapS3FileToOFile(pFile, false);
+ file.sah.flush();
+ if(file.flags & capi.SQLITE_OPEN_DELETEONCLOSE){
+ pool.deletePath(file.path);
+ }
+ }catch(e){
+ return pool.storeErr(e, capi.SQLITE_IOERR);
+ }
+ }
+ return 0;
+ },
+ xDeviceCharacteristics: function(pFile){
+ return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
+ },
+ xFileControl: function(pFile, opId, pArg){
+ return capi.SQLITE_NOTFOUND;
+ },
+ xFileSize: function(pFile,pSz64){
+ const pool = getPoolForPFile(pFile);
+ pool.log(`xFileSize`);
+ const file = pool.getOFileForS3File(pFile);
+ const size = file.sah.getSize() - HEADER_OFFSET_DATA;
+ //log(`xFileSize ${file.path} ${size}`);
+ wasm.poke64(pSz64, BigInt(size));
+ return 0;
+ },
+ xLock: function(pFile,lockType){
+ const pool = getPoolForPFile(pFile);
+ pool.log(`xLock ${lockType}`);
+ pool.storeErr();
+ const file = pool.getOFileForS3File(pFile);
+ file.lockType = lockType;
+ return 0;
+ },
+ xRead: function(pFile,pDest,n,offset64){
+ const pool = getPoolForPFile(pFile);
+ pool.storeErr();
+ const file = pool.getOFileForS3File(pFile);
+ pool.log(`xRead ${file.path} ${n} @ ${offset64}`);
+ try {
+ const nRead = file.sah.read(
+ wasm.heap8u().subarray(pDest, pDest+n),
+ {at: HEADER_OFFSET_DATA + Number(offset64)}
+ );
+ if(nRead < n){
+ wasm.heap8u().fill(0, pDest + nRead, pDest + n);
+ return capi.SQLITE_IOERR_SHORT_READ;
+ }
+ return 0;
+ }catch(e){
+ return pool.storeErr(e, capi.SQLITE_IOERR);
+ }
+ },
+ xSectorSize: function(pFile){
+ return SECTOR_SIZE;
+ },
+ xSync: function(pFile,flags){
+ const pool = getPoolForPFile(pFile);
+ pool.log(`xSync ${flags}`);
+ pool.storeErr();
+ const file = pool.getOFileForS3File(pFile);
+ //log(`xSync ${file.path} ${flags}`);
+ try{
+ file.sah.flush();
+ return 0;
+ }catch(e){
+ return pool.storeErr(e, capi.SQLITE_IOERR);
+ }
+ },
+ xTruncate: function(pFile,sz64){
+ const pool = getPoolForPFile(pFile);
+ pool.log(`xTruncate ${sz64}`);
+ pool.storeErr();
+ const file = pool.getOFileForS3File(pFile);
+ //log(`xTruncate ${file.path} ${iSize}`);
+ try{
+ file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64));
+ return 0;
+ }catch(e){
+ return pool.storeErr(e, capi.SQLITE_IOERR);
+ }
+ },
+ xUnlock: function(pFile,lockType){
+ const pool = getPoolForPFile(pFile);
+ pool.log('xUnlock');
+ const file = pool.getOFileForS3File(pFile);
+ file.lockType = lockType;
+ return 0;
+ },
+ xWrite: function(pFile,pSrc,n,offset64){
+ const pool = getPoolForPFile(pFile);
+ pool.storeErr();
+ const file = pool.getOFileForS3File(pFile);
+ pool.log(`xWrite ${file.path} ${n} ${offset64}`);
+ try{
+ const nBytes = file.sah.write(
+ wasm.heap8u().subarray(pSrc, pSrc+n),
+ { at: HEADER_OFFSET_DATA + Number(offset64) }
+ );
+ return n===nBytes ? 0 : toss("Unknown write() failure.");
+ }catch(e){
+ return pool.storeErr(e, capi.SQLITE_IOERR);
+ }
+ }
+ }/*ioMethods*/;
+
+ const opfsIoMethods = new capi.sqlite3_io_methods();
+ opfsIoMethods.$iVersion = 1;
+ sqlite3.vfs.installVfs({
+ io: {struct: opfsIoMethods, methods: ioMethods}
+ });
+
+ /**
+ Impls for the sqlite3_vfs methods. Maintenance reminder: members
+ are in alphabetical order to simplify finding them.
+ */
+ const vfsMethods = {
+ xAccess: function(pVfs,zName,flags,pOut){
+ //log(`xAccess ${wasm.cstrToJs(zName)}`);
+ const pool = getPoolForVfs(pVfs);
+ pool.storeErr();
+ try{
+ const name = pool.getPath(zName);
+ wasm.poke32(pOut, pool.hasFilename(name) ? 1 : 0);
+ }catch(e){
+ /*ignored*/
+ wasm.poke32(pOut, 0);
+ }
+ return 0;
+ },
+ xCurrentTime: function(pVfs,pOut){
+ wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000),
+ 'double');
+ return 0;
+ },
+ xCurrentTimeInt64: function(pVfs,pOut){
+ wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(),
+ 'i64');
+ return 0;
+ },
+ xDelete: function(pVfs, zName, doSyncDir){
+ const pool = getPoolForVfs(pVfs);
+ pool.log(`xDelete ${wasm.cstrToJs(zName)}`);
+ pool.storeErr();
+ try{
+ pool.deletePath(pool.getPath(zName));
+ return 0;
+ }catch(e){
+ pool.storeErr(e);
+ return capi.SQLITE_IOERR_DELETE;
+ }
+ },
+ xFullPathname: function(pVfs,zName,nOut,pOut){
+ //const pool = getPoolForVfs(pVfs);
+ //pool.log(`xFullPathname ${wasm.cstrToJs(zName)}`);
+ const i = wasm.cstrncpy(pOut, zName, nOut);
+ return i<nOut ? 0 : capi.SQLITE_CANTOPEN;
+ },
+ xGetLastError: function(pVfs,nOut,pOut){
+ const pool = getPoolForVfs(pVfs);
+ const e = pool.popErr();
+ pool.log(`xGetLastError ${nOut} e =`,e);
+ if(e){
+ const scope = wasm.scopedAllocPush();
+ try{
+ const [cMsg, n] = wasm.scopedAllocCString(e.message, true);
+ wasm.cstrncpy(pOut, cMsg, nOut);
+ if(n > nOut) wasm.poke8(pOut + nOut - 1, 0);
+ }catch(e){
+ return capi.SQLITE_NOMEM;
+ }finally{
+ wasm.scopedAllocPop(scope);
+ }
+ }
+ return e ? (e.sqlite3Rc || capi.SQLITE_IOERR) : 0;
+ },
+ //xSleep is optionally defined below
+ xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
+ const pool = getPoolForVfs(pVfs);
+ try{
+ pool.log(`xOpen ${wasm.cstrToJs(zName)} ${flags}`);
+ // First try to open a path that already exists in the file system.
+ const path = (zName && wasm.peek8(zName))
+ ? pool.getPath(zName)
+ : getRandomName();
+ let sah = pool.getSAHForPath(path);
+ if(!sah && (flags & capi.SQLITE_OPEN_CREATE)) {
+ // File not found so try to create it.
+ if(pool.getFileCount() < pool.getCapacity()) {
+ // Choose an unassociated OPFS file from the pool.
+ sah = pool.nextAvailableSAH();
+ pool.setAssociatedPath(sah, path, flags);
+ }else{
+ // File pool is full.
+ toss('SAH pool is full. Cannot create file',path);
+ }
+ }
+ if(!sah){
+ toss('file not found:',path);
+ }
+ // Subsequent I/O methods are only passed the sqlite3_file
+ // pointer, so map the relevant info we need to that pointer.
+ const file = {path, flags, sah};
+ pool.mapS3FileToOFile(pFile, file);
+ file.lockType = capi.SQLITE_LOCK_NONE;
+ const sq3File = new capi.sqlite3_file(pFile);
+ sq3File.$pMethods = opfsIoMethods.pointer;
+ sq3File.dispose();
+ wasm.poke32(pOutFlags, flags);
+ return 0;
+ }catch(e){
+ pool.storeErr(e);
+ return capi.SQLITE_CANTOPEN;
+ }
+ }/*xOpen()*/
+ }/*vfsMethods*/;
+
+ /**
+ Creates and initializes an sqlite3_vfs instance for an
+ OpfsSAHPool. The argument is the VFS's name (JS string).
+
+ Throws if the VFS name is already registered or if something
+ goes terribly wrong via sqlite3.vfs.installVfs().
+
+ Maintenance reminder: the only detail about the returned object
+ which is specific to any given OpfsSAHPool instance is the $zName
+ member. All other state is identical.
+ */
+ const createOpfsVfs = function(vfsName){
+ if( sqlite3.capi.sqlite3_vfs_find(vfsName)){
+ toss3("VFS name is already registered:", vfsName);
+ }
+ const opfsVfs = new capi.sqlite3_vfs();
+ /* We fetch the default VFS so that we can inherit some
+ methods from it. */
+ const pDVfs = capi.sqlite3_vfs_find(null);
+ const dVfs = pDVfs
+ ? new capi.sqlite3_vfs(pDVfs)
+ : null /* dVfs will be null when sqlite3 is built with
+ SQLITE_OS_OTHER. */;
+ opfsVfs.$iVersion = 2/*yes, two*/;
+ opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
+ opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE;
+ opfsVfs.addOnDispose(
+ opfsVfs.$zName = wasm.allocCString(vfsName),
+ ()=>setPoolForVfs(opfsVfs.pointer, 0)
+ );
+
+ if(dVfs){
+ /* Inherit certain VFS members from the default VFS,
+ if available. */
+ opfsVfs.$xRandomness = dVfs.$xRandomness;
+ opfsVfs.$xSleep = dVfs.$xSleep;
+ dVfs.dispose();
+ }
+ if(!opfsVfs.$xRandomness && !vfsMethods.xRandomness){
+ /* If the default VFS has no xRandomness(), add a basic JS impl... */
+ vfsMethods.xRandomness = function(pVfs, nOut, pOut){
+ const heap = wasm.heap8u();
+ let i = 0;
+ for(; i < nOut; ++i) heap[pOut + i] = (Math.random()*255000) & 0xFF;
+ return i;
+ };
+ }
+ if(!opfsVfs.$xSleep && !vfsMethods.xSleep){
+ vfsMethods.xSleep = (pVfs,ms)=>0;
+ }
+ sqlite3.vfs.installVfs({
+ vfs: {struct: opfsVfs, methods: vfsMethods}
+ });
+ return opfsVfs;
+ };
+
+ /**
+ Class for managing OPFS-related state for the
+ OPFS SharedAccessHandle Pool sqlite3_vfs.
+ */
+ class OpfsSAHPool {
+ /* OPFS dir in which VFS metadata is stored. */
+ vfsDir;
+ /* Directory handle to this.vfsDir. */
+ #dhVfsRoot;
+ /* Directory handle to the subdir of this.#dhVfsRoot which holds
+ the randomly-named "opaque" files. This subdir exists in the
+ hope that we can eventually support client-created files in
+ this.#dhVfsRoot. */
+ #dhOpaque;
+ /* Directory handle to this.dhVfsRoot's parent dir. Needed
+ for a VFS-wipe op. */
+ #dhVfsParent;
+ /* Maps SAHs to their opaque file names. */
+ #mapSAHToName = new Map();
+ /* Maps client-side file names to SAHs. */
+ #mapFilenameToSAH = new Map();
+ /* Set of currently-unused SAHs. */
+ #availableSAH = new Set();
+ /* Maps (sqlite3_file*) to xOpen's file objects. */
+ #mapS3FileToOFile_ = new Map();
+
+ /* Maps SAH to an abstract File Object which contains
+ various metadata about that handle. */
+ //#mapSAHToMeta = new Map();
+
+ /** Buffer used by [sg]etAssociatedPath(). */
+ #apBody = new Uint8Array(HEADER_CORPUS_SIZE);
+ // DataView for this.#apBody
+ #dvBody;
+
+ // associated sqlite3_vfs instance
+ #cVfs;
+
+ // Logging verbosity. See optionDefaults.verbosity.
+ #verbosity;
+
+ constructor(options = Object.create(null)){
+ this.#verbosity = options.verbosity ?? optionDefaults.verbosity;
+ this.vfsName = options.name || optionDefaults.name;
+ this.#cVfs = createOpfsVfs(this.vfsName);
+ setPoolForVfs(this.#cVfs.pointer, this);
+ this.vfsDir = options.directory || ("."+this.vfsName);
+ this.#dvBody =
+ new DataView(this.#apBody.buffer, this.#apBody.byteOffset);
+ this.isReady = this
+ .reset(!!(options.clearOnInit ?? optionDefaults.clearOnInit))
+ .then(()=>{
+ if(this.$error) throw this.$error;
+ return this.getCapacity()
+ ? Promise.resolve(undefined)
+ : this.addCapacity(options.initialCapacity
+ || optionDefaults.initialCapacity);
+ });
+ }
+
+ #logImpl(level,...args){
+ if(this.#verbosity>level) loggers[level](this.vfsName+":",...args);
+ };
+ log(...args){this.#logImpl(2, ...args)};
+ warn(...args){this.#logImpl(1, ...args)};
+ error(...args){this.#logImpl(0, ...args)};
+
+ getVfs(){return this.#cVfs}
+
+ /* Current pool capacity. */
+ getCapacity(){return this.#mapSAHToName.size}
+
+ /* Current number of in-use files from pool. */
+ getFileCount(){return this.#mapFilenameToSAH.size}
+
+ /* Returns an array of the names of all
+ currently-opened client-specified filenames. */
+ getFileNames(){
+ const rc = [];
+ const iter = this.#mapFilenameToSAH.keys();
+ for(const n of iter) rc.push(n);
+ return rc;
+ }
+
+// #createFileObject(sah,clientName,opaqueName){
+// const f = Object.assign(Object.create(null),{
+// clientName, opaqueName
+// });
+// this.#mapSAHToMeta.set(sah, f);
+// return f;
+// }
+// #unmapFileObject(sah){
+// this.#mapSAHToMeta.delete(sah);
+// }
+
+ /**
+ Adds n files to the pool's capacity. This change is
+ persistent across settings. Returns a Promise which resolves
+ to the new capacity.
+ */
+ async addCapacity(n){
+ for(let i = 0; i < n; ++i){
+ const name = getRandomName();
+ const h = await this.#dhOpaque.getFileHandle(name, {create:true});
+ const ah = await h.createSyncAccessHandle();
+ this.#mapSAHToName.set(ah,name);
+ this.setAssociatedPath(ah, '', 0);
+ //this.#createFileObject(ah,undefined,name);
+ }
+ return this.getCapacity();
+ }
+
+ /**
+ Reduce capacity by n, but can only reduce up to the limit
+ of currently-available SAHs. Returns a Promise which resolves
+ to the number of slots really removed.
+ */
+ async reduceCapacity(n){
+ let nRm = 0;
+ for(const ah of Array.from(this.#availableSAH)){
+ if(nRm === n || this.getFileCount() === this.getCapacity()){
+ break;
+ }
+ const name = this.#mapSAHToName.get(ah);
+ //this.#unmapFileObject(ah);
+ ah.close();
+ await this.#dhOpaque.removeEntry(name);
+ this.#mapSAHToName.delete(ah);
+ this.#availableSAH.delete(ah);
+ ++nRm;
+ }
+ return nRm;
+ }
+
+ /**
+ Releases all currently-opened SAHs. The only legal
+ operation after this is acquireAccessHandles().
+ */
+ releaseAccessHandles(){
+ for(const ah of this.#mapSAHToName.keys()) ah.close();
+ this.#mapSAHToName.clear();
+ this.#mapFilenameToSAH.clear();
+ this.#availableSAH.clear();
+ }
+
+ /**
+ Opens all files under this.vfsDir/this.#dhOpaque and acquires
+ a SAH for each. returns a Promise which resolves to no value
+ but completes once all SAHs are acquired. If acquiring an SAH
+ throws, SAHPool.$error will contain the corresponding
+ exception.
+
+ If clearFiles is true, the client-stored state of each file is
+ cleared when its handle is acquired, including its name, flags,
+ and any data stored after the metadata block.
+ */
+ async acquireAccessHandles(clearFiles){
+ const files = [];
+ for await (const [name,h] of this.#dhOpaque){
+ if('file'===h.kind){
+ files.push([name,h]);
+ }
+ }
+ return Promise.all(files.map(async([name,h])=>{
+ try{
+ const ah = await h.createSyncAccessHandle()
+ this.#mapSAHToName.set(ah, name);
+ if(clearFiles){
+ ah.truncate(HEADER_OFFSET_DATA);
+ this.setAssociatedPath(ah, '', 0);
+ }else{
+ const path = this.getAssociatedPath(ah);
+ if(path){
+ this.#mapFilenameToSAH.set(path, ah);
+ }else{
+ this.#availableSAH.add(ah);
+ }
+ }
+ }catch(e){
+ this.storeErr(e);
+ this.releaseAccessHandles();
+ throw e;
+ }
+ }));
+ }
+
+ /**
+ Given an SAH, returns the client-specified name of
+ that file by extracting it from the SAH's header.
+
+ On error, it disassociates SAH from the pool and
+ returns an empty string.
+ */
+ getAssociatedPath(sah){
+ sah.read(this.#apBody, {at: 0});
+ // Delete any unexpected files left over by previous
+ // untimely errors...
+ const flags = this.#dvBody.getUint32(HEADER_OFFSET_FLAGS);
+ if(this.#apBody[0] &&
+ ((flags & capi.SQLITE_OPEN_DELETEONCLOSE) ||
+ (flags & PERSISTENT_FILE_TYPES)===0)){
+ warn(`Removing file with unexpected flags ${flags.toString(16)}`,
+ this.#apBody);
+ this.setAssociatedPath(sah, '', 0);
+ return '';
+ }
+
+ const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4);
+ sah.read(fileDigest, {at: HEADER_OFFSET_DIGEST});
+ const compDigest = this.computeDigest(this.#apBody);
+ if(fileDigest.every((v,i) => v===compDigest[i])){
+ // Valid digest
+ const pathBytes = this.#apBody.findIndex((v)=>0===v);
+ if(0===pathBytes){
+ // This file is unassociated, so truncate it to avoid
+ // leaving stale db data laying around.
+ sah.truncate(HEADER_OFFSET_DATA);
+ }
+ return pathBytes
+ ? textDecoder.decode(this.#apBody.subarray(0,pathBytes))
+ : '';
+ }else{
+ // Invalid digest
+ warn('Disassociating file with bad digest.');
+ this.setAssociatedPath(sah, '', 0);
+ return '';
+ }
+ }
+
+ /**
+ Stores the given client-defined path and SQLITE_OPEN_xyz flags
+ into the given SAH. If path is an empty string then the file is
+ disassociated from the pool but its previous name is preserved
+ in the metadata.
+ */
+ setAssociatedPath(sah, path, flags){
+ const enc = textEncoder.encodeInto(path, this.#apBody);
+ if(HEADER_MAX_PATH_SIZE <= enc.written + 1/*NUL byte*/){
+ toss("Path too long:",path);
+ }
+ this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE);
+ this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags);
+
+ const digest = this.computeDigest(this.#apBody);
+ sah.write(this.#apBody, {at: 0});
+ sah.write(digest, {at: HEADER_OFFSET_DIGEST});
+ sah.flush();
+
+ if(path){
+ this.#mapFilenameToSAH.set(path, sah);
+ this.#availableSAH.delete(sah);
+ }else{
+ // This is not a persistent file, so eliminate the contents.
+ sah.truncate(HEADER_OFFSET_DATA);
+ this.#availableSAH.add(sah);
+ }
+ }
+
+ /**
+ Computes a digest for the given byte array and returns it as a
+ two-element Uint32Array. This digest gets stored in the
+ metadata for each file as a validation check. Changing this
+ algorithm invalidates all existing databases for this VFS, so
+ don't do that.
+ */
+ computeDigest(byteArray){
+ let h1 = 0xdeadbeef;
+ let h2 = 0x41c6ce57;
+ for(const v of byteArray){
+ h1 = 31 * h1 + (v * 307);
+ h2 = 31 * h2 + (v * 307);
+ }
+ return new Uint32Array([h1>>>0, h2>>>0]);
+ }
+
+ /**
+ Re-initializes the state of the SAH pool, releasing and
+ re-acquiring all handles.
+
+ See acquireAccessHandles() for the specifics of the clearFiles
+ argument.
+ */
+ async reset(clearFiles){
+ await this.isReady;
+ let h = await navigator.storage.getDirectory();
+ let prev, prevName;
+ for(const d of this.vfsDir.split('/')){
+ if(d){
+ prev = h;
+ h = await h.getDirectoryHandle(d,{create:true});
+ }
+ }
+ this.#dhVfsRoot = h;
+ this.#dhVfsParent = prev;
+ this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle(
+ OPAQUE_DIR_NAME,{create:true}
+ );
+ this.releaseAccessHandles();
+ return this.acquireAccessHandles(clearFiles);
+ }
+
+ /**
+ Returns the pathname part of the given argument,
+ which may be any of:
+
+ - a URL object
+ - A JS string representing a file name
+ - Wasm C-string representing a file name
+
+ All "../" parts and duplicate slashes are resolve/removed from
+ the returned result.
+ */
+ getPath(arg) {
+ if(wasm.isPtr(arg)) arg = wasm.cstrToJs(arg);
+ return ((arg instanceof URL)
+ ? arg
+ : new URL(arg, 'file://localhost/')).pathname;
+ }
+
+ /**
+ Removes the association of the given client-specified file
+ name (JS string) from the pool. Returns true if a mapping
+ is found, else false.
+ */
+ deletePath(path) {
+ const sah = this.#mapFilenameToSAH.get(path);
+ if(sah) {
+ // Un-associate the name from the SAH.
+ this.#mapFilenameToSAH.delete(path);
+ this.setAssociatedPath(sah, '', 0);
+ }
+ return !!sah;
+ }
+
+ /**
+ Sets e (an Error object) as this object's current error. Pass a
+ falsy (or no) value to clear it. If code is truthy it is
+ assumed to be an SQLITE_xxx result code, defaulting to
+ SQLITE_IOERR if code is falsy.
+
+ Returns the 2nd argument.
+ */
+ storeErr(e,code){
+ if(e){
+ e.sqlite3Rc = code || capi.SQLITE_IOERR;
+ this.error(e);
+ }
+ this.$error = e;
+ return code;
+ }
+ /**
+ Pops this object's Error object and returns
+ it (a falsy value if no error is set).
+ */
+ popErr(){
+ const rc = this.$error;
+ this.$error = undefined;
+ return rc;
+ }
+
+ /**
+ Returns the next available SAH without removing
+ it from the set.
+ */
+ nextAvailableSAH(){
+ const [rc] = this.#availableSAH.keys();
+ return rc;
+ }
+
+ /**
+ Given an (sqlite3_file*), returns the mapped
+ xOpen file object.
+ */
+ getOFileForS3File(pFile){
+ return this.#mapS3FileToOFile_.get(pFile);
+ }
+ /**
+ Maps or unmaps (if file is falsy) the given (sqlite3_file*)
+ to an xOpen file object and to this pool object.
+ */
+ mapS3FileToOFile(pFile,file){
+ if(file){
+ this.#mapS3FileToOFile_.set(pFile, file);
+ setPoolForPFile(pFile, this);
+ }else{
+ this.#mapS3FileToOFile_.delete(pFile);
+ setPoolForPFile(pFile, false);
+ }
+ }
+
+ /**
+ Returns true if the given client-defined file name is in this
+ object's name-to-SAH map.
+ */
+ hasFilename(name){
+ return this.#mapFilenameToSAH.has(name)
+ }
+
+ /**
+ Returns the SAH associated with the given
+ client-defined file name.
+ */
+ getSAHForPath(path){
+ return this.#mapFilenameToSAH.get(path);
+ }
+
+ /**
+ Removes this object's sqlite3_vfs registration and shuts down
+ this object, releasing all handles, mappings, and whatnot,
+ including deleting its data directory. There is currently no
+ way to "revive" the object and reaquire its resources.
+
+ This function is intended primarily for testing.
+
+ Resolves to true if it did its job, false if the
+ VFS has already been shut down.
+ */
+ async removeVfs(){
+ if(!this.#cVfs.pointer || !this.#dhOpaque) return false;
+ capi.sqlite3_vfs_unregister(this.#cVfs.pointer);
+ this.#cVfs.dispose();
+ delete initPromises[this.vfsName];
+ try{
+ this.releaseAccessHandles();
+ await this.#dhVfsRoot.removeEntry(OPAQUE_DIR_NAME, {recursive: true});
+ this.#dhOpaque = undefined;
+ await this.#dhVfsParent.removeEntry(
+ this.#dhVfsRoot.name, {recursive: true}
+ );
+ this.#dhVfsRoot = this.#dhVfsParent = undefined;
+ }catch(e){
+ sqlite3.config.error(this.vfsName,"removeVfs() failed:",e);
+ /*otherwise ignored - there is no recovery strategy*/
+ }
+ return true;
+ }
+
+
+ //! Documented elsewhere in this file.
+ exportFile(name){
+ const sah = this.#mapFilenameToSAH.get(name) || toss("File not found:",name);
+ const n = sah.getSize() - HEADER_OFFSET_DATA;
+ const b = new Uint8Array(n>0 ? n : 0);
+ if(n>0){
+ const nRead = sah.read(b, {at: HEADER_OFFSET_DATA});
+ if(nRead != n){
+ toss("Expected to read "+n+" bytes but read "+nRead+".");
+ }
+ }
+ return b;
+ }
+
+ //! Impl for importDb() when its 2nd arg is a function.
+ async importDbChunked(name, callback){
+ const sah = this.#mapFilenameToSAH.get(name)
+ || this.nextAvailableSAH()
+ || toss("No available handles to import to.");
+ sah.truncate(0);
+ let nWrote = 0, chunk, checkedHeader = false, err = false;
+ try{
+ while( undefined !== (chunk = await callback()) ){
+ if(chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk);
+ if( 0===nWrote && chunk.byteLength>=15 ){
+ util.affirmDbHeader(chunk);
+ checkedHeader = true;
+ }
+ sah.write(chunk, {at: HEADER_OFFSET_DATA + nWrote});
+ nWrote += chunk.byteLength;
+ }
+ if( nWrote < 512 || 0!==nWrote % 512 ){
+ toss("Input size",nWrote,"is not correct for an SQLite database.");
+ }
+ if( !checkedHeader ){
+ const header = new Uint8Array(20);
+ sah.read( header, {at: 0} );
+ util.affirmDbHeader( header );
+ }
+ sah.write(new Uint8Array([1,1]), {
+ at: HEADER_OFFSET_DATA + 18
+ }/*force db out of WAL mode*/);
+ }catch(e){
+ this.setAssociatedPath(sah, '', 0);
+ throw e;
+ }
+ this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB);
+ return nWrote;
+ }
+
+ //! Documented elsewhere in this file.
+ importDb(name, bytes){
+ if( bytes instanceof ArrayBuffer ) bytes = new Uint8Array(bytes);
+ else if( bytes instanceof Function ) return this.importDbChunked(name, bytes);
+ const sah = this.#mapFilenameToSAH.get(name)
+ || this.nextAvailableSAH()
+ || toss("No available handles to import to.");
+ const n = bytes.byteLength;
+ if(n<512 || n%512!=0){
+ toss("Byte array size is invalid for an SQLite db.");
+ }
+ const header = "SQLite format 3";
+ for(let i = 0; i < header.length; ++i){
+ if( header.charCodeAt(i) !== bytes[i] ){
+ toss("Input does not contain an SQLite database header.");
+ }
+ }
+ const nWrote = sah.write(bytes, {at: HEADER_OFFSET_DATA});
+ if(nWrote != n){
+ this.setAssociatedPath(sah, '', 0);
+ toss("Expected to write "+n+" bytes but wrote "+nWrote+".");
+ }else{
+ sah.write(new Uint8Array([1,1]), {at: HEADER_OFFSET_DATA+18}
+ /* force db out of WAL mode */);
+ this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB);
+ }
+ return nWrote;
+ }
+
+ }/*class OpfsSAHPool*/;
+
+
+ /**
+ A OpfsSAHPoolUtil instance is exposed to clients in order to
+ manipulate an OpfsSAHPool object without directly exposing that
+ object and allowing for some semantic changes compared to that
+ class.
+
+ Class docs are in the client-level docs for
+ installOpfsSAHPoolVfs().
+ */
+ class OpfsSAHPoolUtil {
+ /* This object's associated OpfsSAHPool. */
+ #p;
+
+ constructor(sahPool){
+ this.#p = sahPool;
+ this.vfsName = sahPool.vfsName;
+ }
+
+ async addCapacity(n){ return this.#p.addCapacity(n) }
+
+ async reduceCapacity(n){ return this.#p.reduceCapacity(n) }
+
+ getCapacity(){ return this.#p.getCapacity(this.#p) }
+
+ getFileCount(){ return this.#p.getFileCount() }
+ getFileNames(){ return this.#p.getFileNames() }
+
+ async reserveMinimumCapacity(min){
+ const c = this.#p.getCapacity();
+ return (c < min) ? this.#p.addCapacity(min - c) : c;
+ }
+
+ exportFile(name){ return this.#p.exportFile(name) }
+
+ importDb(name, bytes){ return this.#p.importDb(name,bytes) }
+
+ async wipeFiles(){ return this.#p.reset(true) }
+
+ unlink(filename){ return this.#p.deletePath(filename) }
+
+ async removeVfs(){ return this.#p.removeVfs() }
+
+ }/* class OpfsSAHPoolUtil */;
+
+ /**
+ Returns a resolved Promise if the current environment
+ has a "fully-sync" SAH impl, else a rejected Promise.
+ */
+ const apiVersionCheck = async ()=>{
+ const dh = await navigator.storage.getDirectory();
+ const fn = '.opfs-sahpool-sync-check-'+getRandomName();
+ const fh = await dh.getFileHandle(fn, { create: true });
+ const ah = await fh.createSyncAccessHandle();
+ const close = ah.close();
+ await close;
+ await dh.removeEntry(fn);
+ if(close?.then){
+ toss("The local OPFS API is too old for opfs-sahpool:",
+ "it has an async FileSystemSyncAccessHandle.close() method.");
+ }
+ return true;
+ };
+
+ /**
+ installOpfsSAHPoolVfs() asynchronously initializes the OPFS
+ SyncAccessHandle (a.k.a. SAH) Pool VFS. It returns a Promise which
+ either resolves to a utility object described below or rejects with
+ an Error value.
+
+ Initialization of this VFS is not automatic because its
+ registration requires that it lock all resources it
+ will potentially use, even if client code does not want
+ to use them. That, in turn, can lead to locking errors
+ when, for example, one page in a given origin has loaded
+ this VFS but does not use it, then another page in that
+ origin tries to use the VFS. If the VFS were automatically
+ registered, the second page would fail to load the VFS
+ due to OPFS locking errors.
+
+ If this function is called more than once with a given "name"
+ option (see below), it will return the same Promise. Calls for
+ different names will return different Promises which resolve to
+ independent objects and refer to different VFS registrations.
+
+ On success, the resulting Promise resolves to a utility object
+ which can be used to query and manipulate the pool. Its API is
+ described at the end of these docs.
+
+ This function accepts an options object to configure certain
+ parts but it is only acknowledged for the very first call and
+ ignored for all subsequent calls.
+
+ The options, in alphabetical order:
+
+ - `clearOnInit`: (default=false) if truthy, contents and filename
+ mapping are removed from each SAH it is acquired during
+ initalization of the VFS, leaving the VFS's storage in a pristine
+ state. Use this only for databases which need not survive a page
+ reload.
+
+ - `initialCapacity`: (default=6) Specifies the default capacity of
+ the VFS. This should not be set unduly high because the VFS has
+ to open (and keep open) a file for each entry in the pool. This
+ setting only has an effect when the pool is initially empty. It
+ does not have any effect if a pool already exists.
+
+ - `directory`: (default="."+`name`) Specifies the OPFS directory
+ name in which to store metadata for the `"opfs-sahpool"`
+ sqlite3_vfs. Only one instance of this VFS can be installed per
+ JavaScript engine, and any two engines with the same storage
+ directory name will collide with each other, leading to locking
+ errors and the inability to register the VFS in the second and
+ subsequent engine. Using a different directory name for each
+ application enables different engines in the same HTTP origin to
+ co-exist, but their data are invisible to each other. Changing
+ this name will effectively orphan any databases stored under
+ previous names. The default is unspecified but descriptive. This
+ option may contain multiple path elements, e.g. "foo/bar/baz",
+ and they are created automatically. In practice there should be
+ no driving need to change this. ACHTUNG: all files in this
+ directory are assumed to be managed by the VFS. Do not place
+ other files in that directory, as they may be deleted or
+ otherwise modified by the VFS.
+
+ - `name`: (default="opfs-sahpool") sets the name to register this
+ VFS under. Normally this should not be changed, but it is
+ possible to register this VFS under multiple names so long as
+ each has its own separate directory to work from. The storage for
+ each is invisible to all others. The name must be a string
+ compatible with `sqlite3_vfs_register()` and friends and suitable
+ for use in URI-style database file names.
+
+ Achtung: if a custom `name` is provided, a custom `directory`
+ must also be provided if any other instance is registered with
+ the default directory. If no directory is explicitly provided
+ then a directory name is synthesized from the `name` option.
+
+
+ - `forceReinitIfPreviouslyFailed`: (default=`false`) Is a fallback option
+ to assist in working around certain flaky environments which may
+ mysteriously fail to permit access to OPFS sync access handles on
+ an initial attempt but permit it on a second attemp. This option
+ should never be used but is provided for those who choose to
+ throw caution to the wind and trust such environments. If this
+ option is truthy _and_ the previous attempt to initialize this
+ VFS with the same `name` failed, the VFS will attempt to
+ initialize a second time instead of returning the cached
+ failure. See discussion at:
+ <https://github.com/sqlite/sqlite-wasm/issues/79>
+
+
+ Peculiarities of this VFS vis a vis other SQLite VFSes:
+
+ - Paths given to it _must_ be absolute. Relative paths will not
+ be properly recognized. This is arguably a bug but correcting it
+ requires some hoop-jumping in routines which have no business
+ doing such tricks.
+
+ - It is possible to install multiple instances under different
+ names, each sandboxed from one another inside their own private
+ directory. This feature exists primarily as a way for disparate
+ applications within a given HTTP origin to use this VFS without
+ introducing locking issues between them.
+
+
+ The API for the utility object passed on by this function's
+ Promise, in alphabetical order...
+
+ - [async] number addCapacity(n)
+
+ Adds `n` entries to the current pool. This change is persistent
+ across sessions so should not be called automatically at each app
+ startup (but see `reserveMinimumCapacity()`). Its returned Promise
+ resolves to the new capacity. Because this operation is necessarily
+ asynchronous, the C-level VFS API cannot call this on its own as
+ needed.
+
+ - byteArray exportFile(name)
+
+ Synchronously reads the contents of the given file into a Uint8Array
+ and returns it. This will throw if the given name is not currently
+ in active use or on I/O error. Note that the given name is _not_
+ visible directly in OPFS (or, if it is, it's not from this VFS).
+
+ - number getCapacity()
+
+ Returns the number of files currently contained
+ in the SAH pool. The default capacity is only large enough for one
+ or two databases and their associated temp files.
+
+ - number getFileCount()
+
+ Returns the number of files from the pool currently allocated to
+ slots. This is not the same as the files being "opened".
+
+ - array getFileNames()
+
+ Returns an array of the names of the files currently allocated to
+ slots. This list is the same length as getFileCount().
+
+ - void importDb(name, bytes)
+
+ Imports the contents of an SQLite database, provided as a byte
+ array or ArrayBuffer, under the given name, overwriting any
+ existing content. Throws if the pool has no available file slots,
+ on I/O error, or if the input does not appear to be a
+ database. In the latter case, only a cursory examination is made.
+ Results are undefined if the given db name refers to an opened
+ db. Note that this routine is _only_ for importing database
+ files, not arbitrary files, the reason being that this VFS will
+ automatically clean up any non-database files so importing them
+ is pointless.
+
+ If passed a function for its second argument, its behavior
+ changes to asynchronous and it imports its data in chunks fed to
+ it by the given callback function. It calls the callback (which
+ may be async) repeatedly, expecting either a Uint8Array or
+ ArrayBuffer (to denote new input) or undefined (to denote
+ EOF). For so long as the callback continues to return
+ non-undefined, it will append incoming data to the given
+ VFS-hosted database file. The result of the resolved Promise when
+ called this way is the size of the resulting database.
+
+ On succes this routine rewrites the database header bytes in the
+ output file (not the input array) to force disabling of WAL mode.
+
+ On a write error, the handle is removed from the pool and made
+ available for re-use.
+
+ - [async] number reduceCapacity(n)
+
+ Removes up to `n` entries from the pool, with the caveat that it can
+ only remove currently-unused entries. It returns a Promise which
+ resolves to the number of entries actually removed.
+
+ - [async] boolean removeVfs()
+
+ Unregisters the opfs-sahpool VFS and removes its directory from OPFS
+ (which means that _all client content_ is removed). After calling
+ this, the VFS may no longer be used and there is no way to re-add it
+ aside from reloading the current JavaScript context.
+
+ Results are undefined if a database is currently in use with this
+ VFS.
+
+ The returned Promise resolves to true if it performed the removal
+ and false if the VFS was not installed.
+
+ If the VFS has a multi-level directory, e.g. "/foo/bar/baz", _only_
+ the bottom-most directory is removed because this VFS cannot know for
+ certain whether the higher-level directories contain data which
+ should be removed.
+
+ - [async] number reserveMinimumCapacity(min)
+
+ If the current capacity is less than `min`, the capacity is
+ increased to `min`, else this returns with no side effects. The
+ resulting Promise resolves to the new capacity.
+
+ - boolean unlink(filename)
+
+ If a virtual file exists with the given name, disassociates it from
+ the pool and returns true, else returns false without side
+ effects. Results are undefined if the file is currently in active
+ use.
+
+ - string vfsName
+
+ The SQLite VFS name under which this pool's VFS is registered.
+
+ - [async] void wipeFiles()
+
+ Clears all client-defined state of all SAHs and makes all of them
+ available for re-use by the pool. Results are undefined if any such
+ handles are currently in use, e.g. by an sqlite3 db.
+ */
+ sqlite3.installOpfsSAHPoolVfs = async function(options=Object.create(null)){
+ options = Object.assign(Object.create(null), optionDefaults, (options||{}));
+ const vfsName = options.name;
+ if(options.$testThrowPhase1){
+ throw options.$testThrowPhase1;
+ }
+ if(initPromises[vfsName]){
+ try {
+ const p = await initPromises[vfsName];
+ //log("installOpfsSAHPoolVfs() returning cached result",options,vfsName,p);
+ return p;
+ }catch(e){
+ //log("installOpfsSAHPoolVfs() got cached failure",options,vfsName,e);
+ if( options.forceReinitIfPreviouslyFailed ){
+ delete initPromises[vfsName];
+ /* Fall through and try again. */
+ }else{
+ throw e;
+ }
+ }
+ }
+ if(!globalThis.FileSystemHandle ||
+ !globalThis.FileSystemDirectoryHandle ||
+ !globalThis.FileSystemFileHandle ||
+ !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle ||
+ !navigator?.storage?.getDirectory){
+ return (initPromises[vfsName] = Promise.reject(new Error("Missing required OPFS APIs.")));
+ }
+
+ /**
+ Maintenance reminder: the order of ASYNC ops in this function
+ is significant. We need to have them all chained at the very
+ end in order to be able to catch a race condition where
+ installOpfsSAHPoolVfs() is called twice in rapid succession,
+ e.g.:
+
+ installOpfsSAHPoolVfs().then(console.warn.bind(console));
+ installOpfsSAHPoolVfs().then(console.warn.bind(console));
+
+ If the timing of the async calls is not "just right" then that
+ second call can end up triggering the init a second time and chaos
+ ensues.
+ */
+ return initPromises[vfsName] = apiVersionCheck().then(async function(){
+ if(options.$testThrowPhase2){
+ throw options.$testThrowPhase2;
+ }
+ const thePool = new OpfsSAHPool(options);
+ return thePool.isReady.then(async()=>{
+ /** The poolUtil object will be the result of the
+ resolved Promise. */
+ const poolUtil = new OpfsSAHPoolUtil(thePool);
+ if(sqlite3.oo1){
+ const oo1 = sqlite3.oo1;
+ const theVfs = thePool.getVfs();
+ const OpfsSAHPoolDb = function(...args){
+ const opt = oo1.DB.dbCtorHelper.normalizeArgs(...args);
+ opt.vfs = theVfs.$zName;
+ oo1.DB.dbCtorHelper.call(this, opt);
+ };
+ OpfsSAHPoolDb.prototype = Object.create(oo1.DB.prototype);
+ poolUtil.OpfsSAHPoolDb = OpfsSAHPoolDb;
+ }/*extend sqlite3.oo1*/
+ thePool.log("VFS initialized.");
+ return poolUtil;
+ }).catch(async (e)=>{
+ await thePool.removeVfs().catch(()=>{});
+ throw e;
+ });
+ }).catch((err)=>{
+ //error("rejecting promise:",err);
+ return initPromises[vfsName] = Promise.reject(err);
+ });
+ }/*installOpfsSAHPoolVfs()*/;
+}/*sqlite3ApiBootstrap.initializers*/);
+/* END FILE: api/sqlite3-vfs-opfs-sahpool.c-pp.js */
+/* BEGIN FILE: api/sqlite3-api-cleanup.js */
+/*
+ 2022-07-22
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ This file is the tail end of the sqlite3-api.js constellation,
+ intended to be appended after all other sqlite3-api-*.js files so
+ that it can finalize any setup and clean up any global symbols
+ temporarily used for setting up the API's various subsystems.
+*/
+'use strict';
+if('undefined' !== typeof Module){ // presumably an Emscripten build
+ /**
+ Install a suitable default configuration for sqlite3ApiBootstrap().
+ */
+ const SABC = Object.assign(
+ Object.create(null), {
+ exports: ('undefined'===typeof wasmExports)
+ ? Module['asm']/* emscripten <=3.1.43 */
+ : wasmExports /* emscripten >=3.1.44 */,
+ memory: Module.wasmMemory /* gets set if built with -sIMPORTED_MEMORY */
+ },
+ globalThis.sqlite3ApiConfig || {}
+ );
+
+ /**
+ For current (2022-08-22) purposes, automatically call
+ sqlite3ApiBootstrap(). That decision will be revisited at some
+ point, as we really want client code to be able to call this to
+ configure certain parts. Clients may modify
+ globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default
+ configuration used by a no-args call to sqlite3ApiBootstrap(),
+ but must have first loaded their WASM module in order to be
+ able to provide the necessary configuration state.
+ */
+ //console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig);
+ globalThis.sqlite3ApiConfig = SABC;
+ let sqlite3;
+ try{
+ sqlite3 = globalThis.sqlite3ApiBootstrap();
+ }catch(e){
+ console.error("sqlite3ApiBootstrap() error:",e);
+ throw e;
+ }finally{
+ delete globalThis.sqlite3ApiBootstrap;
+ delete globalThis.sqlite3ApiConfig;
+ }
+
+ Module.sqlite3 = sqlite3 /* Needed for customized sqlite3InitModule() to be able to
+ pass the sqlite3 object off to the client. */;
+}else{
+ console.warn("This is not running in an Emscripten module context, so",
+ "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack",
+ "of config info for the WASM environment.",
+ "It must be called manually.");
+}
+/* END FILE: api/sqlite3-api-cleanup.js */
+/* END FILE: ./bld/sqlite3-api.c-pp.js */
+/* BEGIN FILE: api/post-js-footer.js */
+/* The current function scope was opened via post-js-header.js, which
+ gets prepended to this at build-time. This file closes that
+ scope. */
+})/*postRun.push(...)*/;
+/* END FILE: api/post-js-footer.js */
+// end include: /usr/local/google/home/dlehmann/JetStream/sqlite3/sqlite-src-3470100/ext/wasm/bld/post-js.speedtest1-vanilla.js
+
+// include: postamble_modularize.js
+// In MODULARIZE mode we wrap the generated code in a factory function
+// and return either the Module itself, or a promise of the module.
+//
+// We assign to the `moduleRtn` global here and configure closure to see
+// this as and extern so it won't get minified.
+
+moduleRtn = readyPromise;
+
+// end include: postamble_modularize.js
+
+
+
+ return moduleRtn;
+}
+);
+})();
+if (typeof exports === 'object' && typeof module === 'object')
+ module.exports = sqlite3InitModule;
+else if (typeof define === 'function' && define['amd'])
+ define([], () => sqlite3InitModule);
+
+/* ^^^^ ACHTUNG: blank line at the start is necessary because
+ Emscripten will not add a newline in some cases and we need
+ a blank line for a sed-based kludge for the ES6 build. */
+/* extern-post-js.js must be appended to the resulting sqlite3.js
+ file. It gets its name from being used as the value for the
+ --extern-post-js=... Emscripten flag. Note that this code, unlike
+ most of the associated JS code, runs outside of the
+ Emscripten-generated module init scope, in the current
+ global scope. */
+(function(){
+ /**
+ In order to hide the sqlite3InitModule()'s resulting
+ Emscripten module from downstream clients (and simplify our
+ documentation by being able to elide those details), we hide that
+ function and expose a hand-written sqlite3InitModule() to return
+ the sqlite3 object (most of the time).
+
+ Unfortunately, we cannot modify the module-loader/exporter-based
+ impls which Emscripten installs at some point in the file above
+ this.
+ */
+ const originalInit = sqlite3InitModule;
+ if(!originalInit){
+ throw new Error("Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.");
+ }
+ /**
+ We need to add some state which our custom Module.locateFile()
+ can see, but an Emscripten limitation currently prevents us from
+ attaching it to the sqlite3InitModule function object:
+
+ https://github.com/emscripten-core/emscripten/issues/18071
+
+ The only(?) current workaround is to temporarily stash this state
+ into the global scope and delete it when sqlite3InitModule()
+ is called.
+ */
+ const initModuleState = globalThis.sqlite3InitModuleState = Object.assign(Object.create(null),{
+ moduleScript: globalThis?.document?.currentScript,
+ isWorker: ('undefined' !== typeof WorkerGlobalScope),
+ location: globalThis.location,
+ urlParams: globalThis?.location?.href
+ ? new URL(globalThis.location.href).searchParams
+ : new URLSearchParams()
+ });
+ initModuleState.debugModule =
+ initModuleState.urlParams.has('sqlite3.debugModule')
+ ? (...args)=>console.warn('sqlite3.debugModule:',...args)
+ : ()=>{};
+
+ if(initModuleState.urlParams.has('sqlite3.dir')){
+ initModuleState.sqlite3Dir = initModuleState.urlParams.get('sqlite3.dir') +'/';
+ }else if(initModuleState.moduleScript){
+ const li = initModuleState.moduleScript.src.split('/');
+ li.pop();
+ initModuleState.sqlite3Dir = li.join('/') + '/';
+ }
+
+ globalThis.sqlite3InitModule = function ff(...args){
+ //console.warn("Using replaced sqlite3InitModule()",globalThis.location);
+ return originalInit(...args).then((EmscriptenModule)=>{
+ //console.warn("sqlite3InitModule() returning sqlite3 object.");
+ const s = EmscriptenModule.sqlite3;
+ s.scriptInfo = initModuleState;
+ //console.warn("sqlite3.scriptInfo =",s.scriptInfo);
+ if(ff.__isUnderTest) s.__isUnderTest = true;
+ const f = s.asyncPostInit;
+ delete s.asyncPostInit;
+ return f();
+ }).catch((e)=>{
+ console.error("Exception loading sqlite3 module:",e);
+ throw e;
+ });
+ };
+ globalThis.sqlite3InitModule.ready = originalInit.ready;
+
+ if(globalThis.sqlite3InitModuleState.moduleScript){
+ const sim = globalThis.sqlite3InitModuleState;
+ let src = sim.moduleScript.src.split('/');
+ src.pop();
+ sim.scriptDir = src.join('/') + '/';
+ }
+ initModuleState.debugModule('sqlite3InitModuleState =',initModuleState);
+ if(0){
+ console.warn("Replaced sqlite3InitModule()");
+ console.warn("globalThis.location.href =",globalThis.location.href);
+ if('undefined' !== typeof document){
+ console.warn("document.currentScript.src =",
+ document?.currentScript?.src);
+ }
+ }
+// Emscripten does not inject these module-loader bits in ES6 module
+// builds and including them here breaks JS bundlers, so elide them
+// from ESM builds.
+ /* Replace the various module exports performed by the Emscripten
+ glue... */
+ if (typeof exports === 'object' && typeof module === 'object'){
+ module.exports = sqlite3InitModule;
+ }else if (typeof exports === 'object'){
+ exports["sqlite3InitModule"] = sqlite3InitModule;
+ }
+ /* AMD modules get injected in a way we cannot override,
+ so we can't handle those here. */
+ return globalThis.sqlite3InitModule /* required for ESM */;
+})();
diff --git a/sqlite3/build/jswasm/speedtest1.wasm b/sqlite3/build/jswasm/speedtest1.wasm
new file mode 100644
index 0000000..6a6e16a
--- /dev/null
+++ b/sqlite3/build/jswasm/speedtest1.wasm
Binary files differ
diff --git a/sqlite3/polyfills.js b/sqlite3/polyfills.js
new file mode 100644
index 0000000..a972f8f
--- /dev/null
+++ b/sqlite3/polyfills.js
@@ -0,0 +1,48 @@
+// Copyright 2024 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Polyfills for missing browser APIs in JavaScript shells.
+
+// `TextEncoder` and `TextDecoder`. These are called only a few times with short
+// ASCII strings, so this is sufficient and not performance-critical.
+class TextEncoder {
+ encode(string) {
+ return Uint8Array.from(string, (char) => {
+ let byte = char.codePointAt(0);
+ if (byte > 0x7f)
+ throw new Error("TextEncoder polyfill only supports ASCII");
+ return byte;
+ });
+ }
+}
+class TextDecoder {
+ decode(array) {
+ for (let byte of array) {
+ if (byte > 0x7f)
+ throw new Error("TextDecoder polyfill only supports ASCII");
+ }
+ return String.fromCharCode.apply(null, array);
+ }
+}
+
+// `crypto.getRandomValues`. This is called only once during setup.
+// The implementation is copied from an Emscripten error message proposing this.
+globalThis.crypto = {
+ getRandomValues: (array) => {
+ for (var i = 0; i < array.length; i++) array[i] = (Math.random() * 256) | 0;
+ },
+};
+
+// Empty `URLSearchParams` has just the same interface as a `Map`.
+globalThis.URLSearchParams = Map;
+
+// `self` global object.
+globalThis.self = this;
+
+globalThis.console = {
+ log: print,
+ debug: print,
+ warn: print,
+ error: print,
+};
diff --git a/wasm/TSF/benchmark.js b/wasm/TSF/benchmark.js
new file mode 100644
index 0000000..405e126
--- /dev/null
+++ b/wasm/TSF/benchmark.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+class Benchmark {
+ async runIteration() {
+ if (!Module._runIteration)
+ await setupModule(Module);
+
+ Module._runIteration(150);
+ }
+};
diff --git a/wasm/TSF/build.log b/wasm/TSF/build.log
new file mode 100644
index 0000000..febb95e
--- /dev/null
+++ b/wasm/TSF/build.log
@@ -0,0 +1,6 @@
+Built on 2024-12-20T14:36:37Z
+
+Toolchain versions
+emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.73-git
+Building...
+Building done
diff --git a/wasm/TSF/build.sh b/wasm/TSF/build.sh
index 45017b1..95995e7 100755
--- a/wasm/TSF/build.sh
+++ b/wasm/TSF/build.sh
@@ -1,6 +1,18 @@
-#!/bin/sh
+#!/bin/bash
+
+set -euo pipefail
+
+touch build.log
+BUILD_LOG="$(realpath build.log)"
+echo "Built on $(date -u '+%Y-%m-%dT%H:%M:%SZ')" | tee "$BUILD_LOG"
+
+echo "Toolchain versions" | tee -a "$BUILD_LOG"
+emcc --version | head -n1 | tee -a "$BUILD_LOG"
+
+echo "Building..." | tee -a "$BUILD_LOG"
+mkdir -p build
emcc \
- -o tsf.html -o tsf.js -O2 -s WASM=1 -s TOTAL_MEMORY=52428800 -g1 \
+ -o build/tsf.js -O2 -s MODULARIZE=1 -s EXPORT_NAME=setupModule -s WASM=1 -s TOTAL_MEMORY=52428800 -g1 --emit-symbol-map -s EXPORTED_FUNCTIONS=_runIteration \
-I. -DTSF_BUILD_SYSTEM=1 \
tsf_asprintf.c\
tsf_buffer.c\
@@ -53,3 +65,4 @@
tsf_ir_different.c\
tsf_ir_speed.c
+echo "Building done" | tee -a "$BUILD_LOG"
diff --git a/wasm/TSF/build/tsf.js b/wasm/TSF/build/tsf.js
new file mode 100644
index 0000000..dab0e9b
--- /dev/null
+++ b/wasm/TSF/build/tsf.js
@@ -0,0 +1,3611 @@
+
+var setupModule = (() => {
+ var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
+ if (typeof __filename != 'undefined') _scriptName = _scriptName || __filename;
+ return (
+function(moduleArg = {}) {
+ var moduleRtn;
+
+// include: shell.js
+// The Module object: Our interface to the outside world. We import
+// and export values on it. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(moduleArg) => Promise<Module>
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to check if Module already exists (e.g. case 3 above).
+// Substitution will be replaced with actual code on later stage of the build,
+// this way Closure Compiler will not mangle it (e.g. case 4. above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module = moduleArg;
+
+// Set up the promise that indicates the Module is initialized
+var readyPromiseResolve, readyPromiseReject;
+
+var readyPromise = new Promise((resolve, reject) => {
+ readyPromiseResolve = resolve;
+ readyPromiseReject = reject;
+});
+
+// Determine the runtime environment we are in. You can customize this by
+// setting the ENVIRONMENT setting at compile time (see settings.js).
+// Attempt to auto-detect the environment
+var ENVIRONMENT_IS_WEB = typeof window == "object";
+
+var ENVIRONMENT_IS_WORKER = typeof WorkerGlobalScope != "undefined";
+
+// N.b. Electron.js environment is simultaneously a NODE-environment, but
+// also a web environment.
+var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string" && process.type != "renderer";
+
+if (ENVIRONMENT_IS_NODE) {}
+
+// --pre-jses are emitted after the Module integration code, so that they can
+// refer to Module (if they choose; they can also define Module)
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = Object.assign({}, Module);
+
+var arguments_ = [];
+
+var thisProgram = "./this.program";
+
+var quit_ = (status, toThrow) => {
+ throw toThrow;
+};
+
+// `/` should be present at the end if `scriptDirectory` is not empty
+var scriptDirectory = "";
+
+function locateFile(path) {
+ if (Module["locateFile"]) {
+ return Module["locateFile"](path, scriptDirectory);
+ }
+ return scriptDirectory + path;
+}
+
+// Hooks that are implemented differently in different runtime environments.
+var readAsync, readBinary;
+
+if (ENVIRONMENT_IS_NODE) {
+ // These modules will usually be used on Node.js. Load them eagerly to avoid
+ // the complexity of lazy-loading.
+ var fs = require("fs");
+ var nodePath = require("path");
+ scriptDirectory = __dirname + "/";
+ // include: node_shell_read.js
+ readBinary = filename => {
+ // We need to re-wrap `file://` strings to URLs. Normalizing isn't
+ // necessary in that case, the path should already be absolute.
+ filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
+ var ret = fs.readFileSync(filename);
+ return ret;
+ };
+ readAsync = (filename, binary = true) => {
+ // See the comment in the `readBinary` function.
+ filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
+ return new Promise((resolve, reject) => {
+ fs.readFile(filename, binary ? undefined : "utf8", (err, data) => {
+ if (err) reject(err); else resolve(binary ? data.buffer : data);
+ });
+ });
+ };
+ // end include: node_shell_read.js
+ if (!Module["thisProgram"] && process.argv.length > 1) {
+ thisProgram = process.argv[1].replace(/\\/g, "/");
+ }
+ arguments_ = process.argv.slice(2);
+ // MODULARIZE will export the module in the proper place outside, we don't need to export here
+ quit_ = (status, toThrow) => {
+ process.exitCode = status;
+ throw toThrow;
+ };
+} else // Note that this includes Node.js workers when relevant (pthreads is enabled).
+// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
+// ENVIRONMENT_IS_NODE.
+if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+ if (ENVIRONMENT_IS_WORKER) {
+ // Check worker, not web, since window could be polyfilled
+ scriptDirectory = self.location.href;
+ } else if (typeof document != "undefined" && document.currentScript) {
+ // web
+ scriptDirectory = document.currentScript.src;
+ }
+ // When MODULARIZE, this JS may be executed later, after document.currentScript
+ // is gone, so we saved it, and we use it here instead of any other info.
+ if (_scriptName) {
+ scriptDirectory = _scriptName;
+ }
+ // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
+ // otherwise, slice off the final part of the url to find the script directory.
+ // if scriptDirectory does not contain a slash, lastIndexOf will return -1,
+ // and scriptDirectory will correctly be replaced with an empty string.
+ // If scriptDirectory contains a query (starting with ?) or a fragment (starting with #),
+ // they are removed because they could contain a slash.
+ if (scriptDirectory.startsWith("blob:")) {
+ scriptDirectory = "";
+ } else {
+ scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1);
+ }
+ {
+ // include: web_or_worker_shell_read.js
+ if (ENVIRONMENT_IS_WORKER) {
+ readBinary = url => {
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", url, false);
+ xhr.responseType = "arraybuffer";
+ xhr.send(null);
+ return new Uint8Array(/** @type{!ArrayBuffer} */ (xhr.response));
+ };
+ }
+ readAsync = url => {
+ // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url.
+ // See https://github.com/github/fetch/pull/92#issuecomment-140665932
+ // Cordova or Electron apps are typically loaded from a file:// url.
+ // So use XHR on webview if URL is a file URL.
+ if (isFileURI(url)) {
+ return new Promise((resolve, reject) => {
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", url, true);
+ xhr.responseType = "arraybuffer";
+ xhr.onload = () => {
+ if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {
+ // file URLs can return 0
+ resolve(xhr.response);
+ return;
+ }
+ reject(xhr.status);
+ };
+ xhr.onerror = reject;
+ xhr.send(null);
+ });
+ }
+ return fetch(url, {
+ credentials: "same-origin"
+ }).then(response => {
+ if (response.ok) {
+ return response.arrayBuffer();
+ }
+ return Promise.reject(new Error(response.status + " : " + response.url));
+ });
+ };
+ }
+} else // end include: web_or_worker_shell_read.js
+{}
+
+var out = Module["print"] || console.log.bind(console);
+
+var err = Module["printErr"] || console.error.bind(console);
+
+// Merge back in the overrides
+Object.assign(Module, moduleOverrides);
+
+// Free the object hierarchy contained in the overrides, this lets the GC
+// reclaim data used.
+moduleOverrides = null;
+
+// Emit code to handle expected values on the Module object. This applies Module.x
+// to the proper local x. This has two benefits: first, we only emit it if it is
+// expected to arrive, and second, by using a local everywhere else that can be
+// minified.
+if (Module["arguments"]) arguments_ = Module["arguments"];
+
+if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
+
+// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
+// end include: shell.js
+// include: preamble.js
+// === Preamble library stuff ===
+// Documentation for the public APIs defined in this file must be updated in:
+// site/source/docs/api_reference/preamble.js.rst
+// A prebuilt local version of the documentation is available at:
+// site/build/text/docs/api_reference/preamble.js.txt
+// You can also build docs locally as HTML or other formats in site/
+// An online HTML version (which may be of a different version of Emscripten)
+// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
+var wasmBinary = Module["wasmBinary"];
+
+// Wasm globals
+var wasmMemory;
+
+//========================================
+// Runtime essentials
+//========================================
+// whether we are quitting the application. no code should run after this.
+// set in exit() and abort()
+var ABORT = false;
+
+// set by exit() and abort(). Passed to 'onExit' handler.
+// NOTE: This is also used as the process return code code in shell environments
+// but only when noExitRuntime is false.
+var EXITSTATUS;
+
+// Memory management
+var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64;
+
+// include: runtime_shared.js
+function updateMemoryViews() {
+ var b = wasmMemory.buffer;
+ Module["HEAP8"] = HEAP8 = new Int8Array(b);
+ Module["HEAP16"] = HEAP16 = new Int16Array(b);
+ Module["HEAPU8"] = HEAPU8 = new Uint8Array(b);
+ Module["HEAPU16"] = HEAPU16 = new Uint16Array(b);
+ Module["HEAP32"] = HEAP32 = new Int32Array(b);
+ Module["HEAPU32"] = HEAPU32 = new Uint32Array(b);
+ Module["HEAPF32"] = HEAPF32 = new Float32Array(b);
+ Module["HEAPF64"] = HEAPF64 = new Float64Array(b);
+}
+
+// end include: runtime_shared.js
+// include: runtime_stack_check.js
+// end include: runtime_stack_check.js
+var __ATPRERUN__ = [];
+
+// functions called before the runtime is initialized
+var __ATINIT__ = [];
+
+// functions called during shutdown
+var __ATPOSTRUN__ = [];
+
+// functions called after the main() is called
+var runtimeInitialized = false;
+
+function preRun() {
+ if (Module["preRun"]) {
+ if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ];
+ while (Module["preRun"].length) {
+ addOnPreRun(Module["preRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function initRuntime() {
+ runtimeInitialized = true;
+ if (!Module["noFSInit"] && !FS.initialized) FS.init();
+ FS.ignorePermissions = false;
+ TTY.init();
+ callRuntimeCallbacks(__ATINIT__);
+}
+
+function postRun() {
+ if (Module["postRun"]) {
+ if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ];
+ while (Module["postRun"].length) {
+ addOnPostRun(Module["postRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+ __ATPRERUN__.unshift(cb);
+}
+
+function addOnInit(cb) {
+ __ATINIT__.unshift(cb);
+}
+
+function addOnPostRun(cb) {
+ __ATPOSTRUN__.unshift(cb);
+}
+
+// include: runtime_math.js
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
+// end include: runtime_math.js
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// Module.preRun (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+
+var runDependencyWatcher = null;
+
+var dependenciesFulfilled = null;
+
+// overridden to take different actions when all run dependencies are fulfilled
+function getUniqueRunDependency(id) {
+ return id;
+}
+
+function addRunDependency(id) {
+ runDependencies++;
+ Module["monitorRunDependencies"]?.(runDependencies);
+}
+
+function removeRunDependency(id) {
+ runDependencies--;
+ Module["monitorRunDependencies"]?.(runDependencies);
+ if (runDependencies == 0) {
+ if (runDependencyWatcher !== null) {
+ clearInterval(runDependencyWatcher);
+ runDependencyWatcher = null;
+ }
+ if (dependenciesFulfilled) {
+ var callback = dependenciesFulfilled;
+ dependenciesFulfilled = null;
+ callback();
+ }
+ }
+}
+
+/** @param {string|number=} what */ function abort(what) {
+ Module["onAbort"]?.(what);
+ what = "Aborted(" + what + ")";
+ // TODO(sbc): Should we remove printing and leave it up to whoever
+ // catches the exception?
+ err(what);
+ ABORT = true;
+ what += ". Build with -sASSERTIONS for more info.";
+ // Use a wasm runtime error, because a JS error might be seen as a foreign
+ // exception, which means we'd run destructors on it. We need the error to
+ // simply make the program stop.
+ // FIXME This approach does not work in Wasm EH because it currently does not assume
+ // all RuntimeErrors are from traps; it decides whether a RuntimeError is from
+ // a trap or not based on a hidden field within the object. So at the moment
+ // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that
+ // allows this in the wasm spec.
+ // Suppress closure compiler warning here. Closure compiler's builtin extern
+ // definition for WebAssembly.RuntimeError claims it takes no arguments even
+ // though it can.
+ // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
+ /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what);
+ readyPromiseReject(e);
+ // Throw the error whether or not MODULARIZE is set because abort is used
+ // in code paths apart from instantiation where an exception is expected
+ // to be thrown when abort is called.
+ throw e;
+}
+
+// include: memoryprofiler.js
+// end include: memoryprofiler.js
+// include: URIUtils.js
+// Prefix of data URIs emitted by SINGLE_FILE and related options.
+var dataURIPrefix = "data:application/octet-stream;base64,";
+
+/**
+ * Indicates whether filename is a base64 data URI.
+ * @noinline
+ */ var isDataURI = filename => filename.startsWith(dataURIPrefix);
+
+/**
+ * Indicates whether filename is delivered via file protocol (as opposed to http/https)
+ * @noinline
+ */ var isFileURI = filename => filename.startsWith("file://");
+
+// end include: URIUtils.js
+// include: runtime_exceptions.js
+// end include: runtime_exceptions.js
+function findWasmBinary() {
+ var f = "tsf.wasm";
+ if (!isDataURI(f)) {
+ return locateFile(f);
+ }
+ return f;
+}
+
+var wasmBinaryFile;
+
+function getBinarySync(file) {
+ if (file == wasmBinaryFile && wasmBinary) {
+ return new Uint8Array(wasmBinary);
+ }
+ if (readBinary) {
+ return readBinary(file);
+ }
+ throw "both async and sync fetching of the wasm failed";
+}
+
+function getBinaryPromise(binaryFile) {
+ // If we don't have the binary yet, load it asynchronously using readAsync.
+ if (!wasmBinary) {
+ // Fetch the binary using readAsync
+ return readAsync(binaryFile).then(response => new Uint8Array(/** @type{!ArrayBuffer} */ (response)), // Fall back to getBinarySync if readAsync fails
+ () => getBinarySync(binaryFile));
+ }
+ // Otherwise, getBinarySync should be able to get it synchronously
+ return Promise.resolve().then(() => getBinarySync(binaryFile));
+}
+
+function instantiateArrayBuffer(binaryFile, imports, receiver) {
+ return getBinaryPromise(binaryFile).then(binary => WebAssembly.instantiate(binary, imports)).then(receiver, reason => {
+ err(`failed to asynchronously prepare wasm: ${reason}`);
+ abort(reason);
+ });
+}
+
+function instantiateAsync(binary, binaryFile, imports, callback) {
+ if (!binary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(binaryFile) && // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously.
+ !isFileURI(binaryFile) && // Avoid instantiateStreaming() on Node.js environment for now, as while
+ // Node.js v18.1.0 implements it, it does not have a full fetch()
+ // implementation yet.
+ // Reference:
+ // https://github.com/emscripten-core/emscripten/pull/16917
+ !ENVIRONMENT_IS_NODE && typeof fetch == "function") {
+ return fetch(binaryFile, {
+ credentials: "same-origin"
+ }).then(response => {
+ // Suppress closure warning here since the upstream definition for
+ // instantiateStreaming only allows Promise<Repsponse> rather than
+ // an actual Response.
+ // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed.
+ /** @suppress {checkTypes} */ var result = WebAssembly.instantiateStreaming(response, imports);
+ return result.then(callback, function(reason) {
+ // We expect the most common failure cause to be a bad MIME type for the binary,
+ // in which case falling back to ArrayBuffer instantiation should work.
+ err(`wasm streaming compile failed: ${reason}`);
+ err("falling back to ArrayBuffer instantiation");
+ return instantiateArrayBuffer(binaryFile, imports, callback);
+ });
+ });
+ }
+ return instantiateArrayBuffer(binaryFile, imports, callback);
+}
+
+function getWasmImports() {
+ // prepare imports
+ return {
+ "env": wasmImports,
+ "wasi_snapshot_preview1": wasmImports
+ };
+}
+
+// Create the wasm instance.
+// Receives the wasm imports, returns the exports.
+function createWasm() {
+ // Load the wasm module and create an instance of using native support in the JS engine.
+ // handle a generated wasm instance, receiving its exports and
+ // performing other necessary setup
+ /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) {
+ wasmExports = instance.exports;
+ wasmMemory = wasmExports["memory"];
+ updateMemoryViews();
+ addOnInit(wasmExports["__wasm_call_ctors"]);
+ removeRunDependency("wasm-instantiate");
+ return wasmExports;
+ }
+ // wait for the pthread pool (if any)
+ addRunDependency("wasm-instantiate");
+ // Prefer streaming instantiation if available.
+ function receiveInstantiationResult(result) {
+ // 'result' is a ResultObject object which has both the module and instance.
+ // receiveInstance() will swap in the exports (to Module.asm) so they can be called
+ // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
+ // When the regression is fixed, can restore the above PTHREADS-enabled path.
+ receiveInstance(result["instance"]);
+ }
+ var info = getWasmImports();
+ // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
+ // to manually instantiate the Wasm module themselves. This allows pages to
+ // run the instantiation parallel to any other async startup actions they are
+ // performing.
+ // Also pthreads and wasm workers initialize the wasm instance through this
+ // path.
+ if (Module["instantiateWasm"]) {
+ try {
+ return Module["instantiateWasm"](info, receiveInstance);
+ } catch (e) {
+ err(`Module.instantiateWasm callback failed with error: ${e}`);
+ // If instantiation fails, reject the module ready promise.
+ readyPromiseReject(e);
+ }
+ }
+ wasmBinaryFile ??= findWasmBinary();
+ // If instantiation fails, reject the module ready promise.
+ instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject);
+ return {};
+}
+
+// Globals used by JS i64 conversions (see makeSetValue)
+var tempDouble;
+
+var tempI64;
+
+// include: runtime_debug.js
+// end include: runtime_debug.js
+// === Body ===
+// end include: preamble.js
+class ExitStatus {
+ name="ExitStatus";
+ constructor(status) {
+ this.message = `Program terminated with exit(${status})`;
+ this.status = status;
+ }
+}
+
+var callRuntimeCallbacks = callbacks => {
+ while (callbacks.length > 0) {
+ // Pass the module as the first argument.
+ callbacks.shift()(Module);
+ }
+};
+
+var noExitRuntime = Module["noExitRuntime"] || true;
+
+/** @suppress {duplicate } */ var syscallGetVarargI = () => {
+ // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number.
+ var ret = HEAP32[((+SYSCALLS.varargs) >> 2)];
+ SYSCALLS.varargs += 4;
+ return ret;
+};
+
+var syscallGetVarargP = syscallGetVarargI;
+
+var PATH = {
+ isAbs: path => path.charAt(0) === "/",
+ splitPath: filename => {
+ var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+ return splitPathRe.exec(filename).slice(1);
+ },
+ normalizeArray: (parts, allowAboveRoot) => {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === ".") {
+ parts.splice(i, 1);
+ } else if (last === "..") {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (;up; up--) {
+ parts.unshift("..");
+ }
+ }
+ return parts;
+ },
+ normalize: path => {
+ var isAbsolute = PATH.isAbs(path), trailingSlash = path.substr(-1) === "/";
+ // Normalize the path
+ path = PATH.normalizeArray(path.split("/").filter(p => !!p), !isAbsolute).join("/");
+ if (!path && !isAbsolute) {
+ path = ".";
+ }
+ if (path && trailingSlash) {
+ path += "/";
+ }
+ return (isAbsolute ? "/" : "") + path;
+ },
+ dirname: path => {
+ var result = PATH.splitPath(path), root = result[0], dir = result[1];
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return ".";
+ }
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+ return root + dir;
+ },
+ basename: path => {
+ // EMSCRIPTEN return '/'' for '/', not an empty string
+ if (path === "/") return "/";
+ path = PATH.normalize(path);
+ path = path.replace(/\/$/, "");
+ var lastSlash = path.lastIndexOf("/");
+ if (lastSlash === -1) return path;
+ return path.substr(lastSlash + 1);
+ },
+ join: (...paths) => PATH.normalize(paths.join("/")),
+ join2: (l, r) => PATH.normalize(l + "/" + r)
+};
+
+var initRandomFill = () => {
+ if (typeof crypto == "object" && typeof crypto["getRandomValues"] == "function") {
+ // for modern web browsers
+ return view => crypto.getRandomValues(view);
+ } else if (ENVIRONMENT_IS_NODE) {
+ // for nodejs with or without crypto support included
+ try {
+ var crypto_module = require("crypto");
+ var randomFillSync = crypto_module["randomFillSync"];
+ if (randomFillSync) {
+ // nodejs with LTS crypto support
+ return view => crypto_module["randomFillSync"](view);
+ }
+ // very old nodejs with the original crypto API
+ var randomBytes = crypto_module["randomBytes"];
+ return view => (view.set(randomBytes(view.byteLength)), // Return the original view to match modern native implementations.
+ view);
+ } catch (e) {}
+ }
+ // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096
+ abort("initRandomDevice");
+};
+
+var randomFill = view => (randomFill = initRandomFill())(view);
+
+var PATH_FS = {
+ resolve: (...args) => {
+ var resolvedPath = "", resolvedAbsolute = false;
+ for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? args[i] : FS.cwd();
+ // Skip empty and invalid entries
+ if (typeof path != "string") {
+ throw new TypeError("Arguments to path.resolve must be strings");
+ } else if (!path) {
+ return "";
+ }
+ // an invalid portion invalidates the whole thing
+ resolvedPath = path + "/" + resolvedPath;
+ resolvedAbsolute = PATH.isAbs(path);
+ }
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+ resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(p => !!p), !resolvedAbsolute).join("/");
+ return ((resolvedAbsolute ? "/" : "") + resolvedPath) || ".";
+ },
+ relative: (from, to) => {
+ from = PATH_FS.resolve(from).substr(1);
+ to = PATH_FS.resolve(to).substr(1);
+ function trim(arr) {
+ var start = 0;
+ for (;start < arr.length; start++) {
+ if (arr[start] !== "") break;
+ }
+ var end = arr.length - 1;
+ for (;end >= 0; end--) {
+ if (arr[end] !== "") break;
+ }
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+ var fromParts = trim(from.split("/"));
+ var toParts = trim(to.split("/"));
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push("..");
+ }
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+ return outputParts.join("/");
+ }
+};
+
+var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder : undefined;
+
+/**
+ * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given
+ * array that contains uint8 values, returns a copy of that string as a
+ * Javascript String object.
+ * heapOrArray is either a regular array, or a JavaScript typed array view.
+ * @param {number=} idx
+ * @param {number=} maxBytesToRead
+ * @return {string}
+ */ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => {
+ var endIdx = idx + maxBytesToRead;
+ var endPtr = idx;
+ // TextDecoder needs to know the byte length in advance, it doesn't stop on
+ // null terminator by itself. Also, use the length info to avoid running tiny
+ // strings through TextDecoder, since .subarray() allocates garbage.
+ // (As a tiny code save trick, compare endPtr against endIdx using a negation,
+ // so that undefined/NaN means Infinity)
+ while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
+ if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
+ return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
+ }
+ var str = "";
+ // If building with TextDecoder, we have already computed the string length
+ // above, so test loop end condition against that
+ while (idx < endPtr) {
+ // For UTF8 byte structure, see:
+ // http://en.wikipedia.org/wiki/UTF-8#Description
+ // https://www.ietf.org/rfc/rfc2279.txt
+ // https://tools.ietf.org/html/rfc3629
+ var u0 = heapOrArray[idx++];
+ if (!(u0 & 128)) {
+ str += String.fromCharCode(u0);
+ continue;
+ }
+ var u1 = heapOrArray[idx++] & 63;
+ if ((u0 & 224) == 192) {
+ str += String.fromCharCode(((u0 & 31) << 6) | u1);
+ continue;
+ }
+ var u2 = heapOrArray[idx++] & 63;
+ if ((u0 & 240) == 224) {
+ u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
+ } else {
+ u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
+ }
+ if (u0 < 65536) {
+ str += String.fromCharCode(u0);
+ } else {
+ var ch = u0 - 65536;
+ str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));
+ }
+ }
+ return str;
+};
+
+var FS_stdin_getChar_buffer = [];
+
+var lengthBytesUTF8 = str => {
+ var len = 0;
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
+ // unit, not a Unicode code point of the character! So decode
+ // UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ var c = str.charCodeAt(i);
+ // possibly a lead surrogate
+ if (c <= 127) {
+ len++;
+ } else if (c <= 2047) {
+ len += 2;
+ } else if (c >= 55296 && c <= 57343) {
+ len += 4;
+ ++i;
+ } else {
+ len += 3;
+ }
+ }
+ return len;
+};
+
+var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
+ // Parameter maxBytesToWrite is not optional. Negative values, 0, null,
+ // undefined and false each don't write out any bytes.
+ if (!(maxBytesToWrite > 0)) return 0;
+ var startIdx = outIdx;
+ var endIdx = outIdx + maxBytesToWrite - 1;
+ // -1 for string null terminator.
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
+ // unit, not a Unicode code point of the character! So decode
+ // UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description
+ // and https://www.ietf.org/rfc/rfc2279.txt
+ // and https://tools.ietf.org/html/rfc3629
+ var u = str.charCodeAt(i);
+ // possibly a lead surrogate
+ if (u >= 55296 && u <= 57343) {
+ var u1 = str.charCodeAt(++i);
+ u = 65536 + ((u & 1023) << 10) | (u1 & 1023);
+ }
+ if (u <= 127) {
+ if (outIdx >= endIdx) break;
+ heap[outIdx++] = u;
+ } else if (u <= 2047) {
+ if (outIdx + 1 >= endIdx) break;
+ heap[outIdx++] = 192 | (u >> 6);
+ heap[outIdx++] = 128 | (u & 63);
+ } else if (u <= 65535) {
+ if (outIdx + 2 >= endIdx) break;
+ heap[outIdx++] = 224 | (u >> 12);
+ heap[outIdx++] = 128 | ((u >> 6) & 63);
+ heap[outIdx++] = 128 | (u & 63);
+ } else {
+ if (outIdx + 3 >= endIdx) break;
+ heap[outIdx++] = 240 | (u >> 18);
+ heap[outIdx++] = 128 | ((u >> 12) & 63);
+ heap[outIdx++] = 128 | ((u >> 6) & 63);
+ heap[outIdx++] = 128 | (u & 63);
+ }
+ }
+ // Null-terminate the pointer to the buffer.
+ heap[outIdx] = 0;
+ return outIdx - startIdx;
+};
+
+/** @type {function(string, boolean=, number=)} */ function intArrayFromString(stringy, dontAddNull, length) {
+ var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1;
+ var u8array = new Array(len);
+ var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
+ if (dontAddNull) u8array.length = numBytesWritten;
+ return u8array;
+}
+
+var FS_stdin_getChar = () => {
+ if (!FS_stdin_getChar_buffer.length) {
+ var result = null;
+ if (ENVIRONMENT_IS_NODE) {
+ // we will read data by chunks of BUFSIZE
+ var BUFSIZE = 256;
+ var buf = Buffer.alloc(BUFSIZE);
+ var bytesRead = 0;
+ // For some reason we must suppress a closure warning here, even though
+ // fd definitely exists on process.stdin, and is even the proper way to
+ // get the fd of stdin,
+ // https://github.com/nodejs/help/issues/2136#issuecomment-523649904
+ // This started to happen after moving this logic out of library_tty.js,
+ // so it is related to the surrounding code in some unclear manner.
+ /** @suppress {missingProperties} */ var fd = process.stdin.fd;
+ try {
+ bytesRead = fs.readSync(fd, buf, 0, BUFSIZE);
+ } catch (e) {
+ // Cross-platform differences: on Windows, reading EOF throws an
+ // exception, but on other OSes, reading EOF returns 0. Uniformize
+ // behavior by treating the EOF exception to return 0.
+ if (e.toString().includes("EOF")) bytesRead = 0; else throw e;
+ }
+ if (bytesRead > 0) {
+ result = buf.slice(0, bytesRead).toString("utf-8");
+ }
+ } else if (typeof window != "undefined" && typeof window.prompt == "function") {
+ // Browser.
+ result = window.prompt("Input: ");
+ // returns null on cancel
+ if (result !== null) {
+ result += "\n";
+ }
+ } else {}
+ if (!result) {
+ return null;
+ }
+ FS_stdin_getChar_buffer = intArrayFromString(result, true);
+ }
+ return FS_stdin_getChar_buffer.shift();
+};
+
+var TTY = {
+ ttys: [],
+ init() {},
+ // https://github.com/emscripten-core/emscripten/pull/1555
+ // if (ENVIRONMENT_IS_NODE) {
+ // // currently, FS.init does not distinguish if process.stdin is a file or TTY
+ // // device, it always assumes it's a TTY device. because of this, we're forcing
+ // // process.stdin to UTF8 encoding to at least make stdin reading compatible
+ // // with text files until FS.init can be refactored.
+ // process.stdin.setEncoding('utf8');
+ // }
+ shutdown() {},
+ // https://github.com/emscripten-core/emscripten/pull/1555
+ // if (ENVIRONMENT_IS_NODE) {
+ // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+ // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+ // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+ // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+ // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+ // process.stdin.pause();
+ // }
+ register(dev, ops) {
+ TTY.ttys[dev] = {
+ input: [],
+ output: [],
+ ops
+ };
+ FS.registerDevice(dev, TTY.stream_ops);
+ },
+ stream_ops: {
+ open(stream) {
+ var tty = TTY.ttys[stream.node.rdev];
+ if (!tty) {
+ throw new FS.ErrnoError(43);
+ }
+ stream.tty = tty;
+ stream.seekable = false;
+ },
+ close(stream) {
+ // flush any pending line data
+ stream.tty.ops.fsync(stream.tty);
+ },
+ fsync(stream) {
+ stream.tty.ops.fsync(stream.tty);
+ },
+ read(stream, buffer, offset, length, pos) {
+ /* ignored */ if (!stream.tty || !stream.tty.ops.get_char) {
+ throw new FS.ErrnoError(60);
+ }
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = stream.tty.ops.get_char(stream.tty);
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(6);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset + i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, pos) {
+ if (!stream.tty || !stream.tty.ops.put_char) {
+ throw new FS.ErrnoError(60);
+ }
+ try {
+ for (var i = 0; i < length; i++) {
+ stream.tty.ops.put_char(stream.tty, buffer[offset + i]);
+ }
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ },
+ default_tty_ops: {
+ get_char(tty) {
+ return FS_stdin_getChar();
+ },
+ put_char(tty, val) {
+ if (val === null || val === 10) {
+ out(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ } else {
+ if (val != 0) tty.output.push(val);
+ }
+ },
+ // val == 0 would cut text output off in the middle.
+ fsync(tty) {
+ if (tty.output && tty.output.length > 0) {
+ out(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ }
+ },
+ ioctl_tcgets(tty) {
+ // typical setting
+ return {
+ c_iflag: 25856,
+ c_oflag: 5,
+ c_cflag: 191,
+ c_lflag: 35387,
+ c_cc: [ 3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ };
+ },
+ ioctl_tcsets(tty, optional_actions, data) {
+ // currently just ignore
+ return 0;
+ },
+ ioctl_tiocgwinsz(tty) {
+ return [ 24, 80 ];
+ }
+ },
+ default_tty1_ops: {
+ put_char(tty, val) {
+ if (val === null || val === 10) {
+ err(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ } else {
+ if (val != 0) tty.output.push(val);
+ }
+ },
+ fsync(tty) {
+ if (tty.output && tty.output.length > 0) {
+ err(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ }
+ }
+ }
+};
+
+var mmapAlloc = size => {
+ abort();
+};
+
+var MEMFS = {
+ ops_table: null,
+ mount(mount) {
+ return MEMFS.createNode(null, "/", 16895, 0);
+ },
+ createNode(parent, name, mode, dev) {
+ if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+ // no supported
+ throw new FS.ErrnoError(63);
+ }
+ MEMFS.ops_table ||= {
+ dir: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ lookup: MEMFS.node_ops.lookup,
+ mknod: MEMFS.node_ops.mknod,
+ rename: MEMFS.node_ops.rename,
+ unlink: MEMFS.node_ops.unlink,
+ rmdir: MEMFS.node_ops.rmdir,
+ readdir: MEMFS.node_ops.readdir,
+ symlink: MEMFS.node_ops.symlink
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek
+ }
+ },
+ file: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek,
+ read: MEMFS.stream_ops.read,
+ write: MEMFS.stream_ops.write,
+ allocate: MEMFS.stream_ops.allocate,
+ mmap: MEMFS.stream_ops.mmap,
+ msync: MEMFS.stream_ops.msync
+ }
+ },
+ link: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ readlink: MEMFS.node_ops.readlink
+ },
+ stream: {}
+ },
+ chrdev: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: FS.chrdev_stream_ops
+ }
+ };
+ var node = FS.createNode(parent, name, mode, dev);
+ if (FS.isDir(node.mode)) {
+ node.node_ops = MEMFS.ops_table.dir.node;
+ node.stream_ops = MEMFS.ops_table.dir.stream;
+ node.contents = {};
+ } else if (FS.isFile(node.mode)) {
+ node.node_ops = MEMFS.ops_table.file.node;
+ node.stream_ops = MEMFS.ops_table.file.stream;
+ node.usedBytes = 0;
+ // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.
+ // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred
+ // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size
+ // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme.
+ node.contents = null;
+ } else if (FS.isLink(node.mode)) {
+ node.node_ops = MEMFS.ops_table.link.node;
+ node.stream_ops = MEMFS.ops_table.link.stream;
+ } else if (FS.isChrdev(node.mode)) {
+ node.node_ops = MEMFS.ops_table.chrdev.node;
+ node.stream_ops = MEMFS.ops_table.chrdev.stream;
+ }
+ node.timestamp = Date.now();
+ // add the new node to the parent
+ if (parent) {
+ parent.contents[name] = node;
+ parent.timestamp = node.timestamp;
+ }
+ return node;
+ },
+ getFileDataAsTypedArray(node) {
+ if (!node.contents) return new Uint8Array(0);
+ if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes);
+ // Make sure to not return excess unused bytes.
+ return new Uint8Array(node.contents);
+ },
+ expandFileStorage(node, newCapacity) {
+ var prevCapacity = node.contents ? node.contents.length : 0;
+ if (prevCapacity >= newCapacity) return;
+ // No need to expand, the storage was already large enough.
+ // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity.
+ // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to
+ // avoid overshooting the allocation cap by a very large margin.
+ var CAPACITY_DOUBLING_MAX = 1024 * 1024;
+ newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>> 0);
+ if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);
+ // At minimum allocate 256b for each file when expanding.
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newCapacity);
+ // Allocate new storage.
+ if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0);
+ },
+ // Copy old data over to the new storage.
+ resizeFileStorage(node, newSize) {
+ if (node.usedBytes == newSize) return;
+ if (newSize == 0) {
+ node.contents = null;
+ // Fully decommit when requesting a resize to zero.
+ node.usedBytes = 0;
+ } else {
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newSize);
+ // Allocate new storage.
+ if (oldContents) {
+ node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes)));
+ }
+ // Copy old data over to the new storage.
+ node.usedBytes = newSize;
+ }
+ },
+ node_ops: {
+ getattr(node) {
+ var attr = {};
+ // device numbers reuse inode numbers.
+ attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+ attr.ino = node.id;
+ attr.mode = node.mode;
+ attr.nlink = 1;
+ attr.uid = 0;
+ attr.gid = 0;
+ attr.rdev = node.rdev;
+ if (FS.isDir(node.mode)) {
+ attr.size = 4096;
+ } else if (FS.isFile(node.mode)) {
+ attr.size = node.usedBytes;
+ } else if (FS.isLink(node.mode)) {
+ attr.size = node.link.length;
+ } else {
+ attr.size = 0;
+ }
+ attr.atime = new Date(node.timestamp);
+ attr.mtime = new Date(node.timestamp);
+ attr.ctime = new Date(node.timestamp);
+ // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+ // but this is not required by the standard.
+ attr.blksize = 4096;
+ attr.blocks = Math.ceil(attr.size / attr.blksize);
+ return attr;
+ },
+ setattr(node, attr) {
+ if (attr.mode !== undefined) {
+ node.mode = attr.mode;
+ }
+ if (attr.timestamp !== undefined) {
+ node.timestamp = attr.timestamp;
+ }
+ if (attr.size !== undefined) {
+ MEMFS.resizeFileStorage(node, attr.size);
+ }
+ },
+ lookup(parent, name) {
+ throw MEMFS.doesNotExistError;
+ },
+ mknod(parent, name, mode, dev) {
+ return MEMFS.createNode(parent, name, mode, dev);
+ },
+ rename(old_node, new_dir, new_name) {
+ // if we're overwriting a directory at new_name, make sure it's empty.
+ if (FS.isDir(old_node.mode)) {
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {}
+ if (new_node) {
+ for (var i in new_node.contents) {
+ throw new FS.ErrnoError(55);
+ }
+ }
+ }
+ // do the internal rewiring
+ delete old_node.parent.contents[old_node.name];
+ old_node.parent.timestamp = Date.now();
+ old_node.name = new_name;
+ new_dir.contents[new_name] = old_node;
+ new_dir.timestamp = old_node.parent.timestamp;
+ },
+ unlink(parent, name) {
+ delete parent.contents[name];
+ parent.timestamp = Date.now();
+ },
+ rmdir(parent, name) {
+ var node = FS.lookupNode(parent, name);
+ for (var i in node.contents) {
+ throw new FS.ErrnoError(55);
+ }
+ delete parent.contents[name];
+ parent.timestamp = Date.now();
+ },
+ readdir(node) {
+ var entries = [ ".", ".." ];
+ for (var key of Object.keys(node.contents)) {
+ entries.push(key);
+ }
+ return entries;
+ },
+ symlink(parent, newname, oldpath) {
+ var node = MEMFS.createNode(parent, newname, 511 | 40960, 0);
+ node.link = oldpath;
+ return node;
+ },
+ readlink(node) {
+ if (!FS.isLink(node.mode)) {
+ throw new FS.ErrnoError(28);
+ }
+ return node.link;
+ }
+ },
+ stream_ops: {
+ read(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ if (position >= stream.node.usedBytes) return 0;
+ var size = Math.min(stream.node.usedBytes - position, length);
+ if (size > 8 && contents.subarray) {
+ // non-trivial, and typed array
+ buffer.set(contents.subarray(position, position + size), offset);
+ } else {
+ for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
+ }
+ return size;
+ },
+ write(stream, buffer, offset, length, position, canOwn) {
+ if (!length) return 0;
+ var node = stream.node;
+ node.timestamp = Date.now();
+ if (buffer.subarray && (!node.contents || node.contents.subarray)) {
+ // This write is from a typed array to a typed array?
+ if (canOwn) {
+ node.contents = buffer.subarray(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (node.usedBytes === 0 && position === 0) {
+ // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data.
+ node.contents = buffer.slice(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (position + length <= node.usedBytes) {
+ // Writing to an already allocated and used subrange of the file?
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ return length;
+ }
+ }
+ // Appending to an existing file and we need to reallocate, or source data did not come as a typed array.
+ MEMFS.expandFileStorage(node, position + length);
+ if (node.contents.subarray && buffer.subarray) {
+ // Use typed array write which is available.
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ } else {
+ for (var i = 0; i < length; i++) {
+ node.contents[position + i] = buffer[offset + i];
+ }
+ }
+ node.usedBytes = Math.max(node.usedBytes, position + length);
+ return length;
+ },
+ llseek(stream, offset, whence) {
+ var position = offset;
+ if (whence === 1) {
+ position += stream.position;
+ } else if (whence === 2) {
+ if (FS.isFile(stream.node.mode)) {
+ position += stream.node.usedBytes;
+ }
+ }
+ if (position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ return position;
+ },
+ allocate(stream, offset, length) {
+ MEMFS.expandFileStorage(stream.node, offset + length);
+ stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);
+ },
+ mmap(stream, length, position, prot, flags) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ var ptr;
+ var allocated;
+ var contents = stream.node.contents;
+ // Only make a new copy when MAP_PRIVATE is specified.
+ if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) {
+ // We can't emulate MAP_SHARED when the file is not backed by the
+ // buffer we're mapping to (e.g. the HEAP buffer).
+ allocated = false;
+ ptr = contents.byteOffset;
+ } else {
+ allocated = true;
+ ptr = mmapAlloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(48);
+ }
+ if (contents) {
+ // Try to avoid unnecessary slices.
+ if (position > 0 || position + length < contents.length) {
+ if (contents.subarray) {
+ contents = contents.subarray(position, position + length);
+ } else {
+ contents = Array.prototype.slice.call(contents, position, position + length);
+ }
+ }
+ HEAP8.set(contents, ptr);
+ }
+ }
+ return {
+ ptr,
+ allocated
+ };
+ },
+ msync(stream, buffer, offset, length, mmapFlags) {
+ MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
+ // should we check if bytesWritten and length are the same?
+ return 0;
+ }
+ }
+};
+
+/** @param {boolean=} noRunDep */ var asyncLoad = (url, onload, onerror, noRunDep) => {
+ var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : "";
+ readAsync(url).then(arrayBuffer => {
+ onload(new Uint8Array(arrayBuffer));
+ if (dep) removeRunDependency(dep);
+ }, err => {
+ if (onerror) {
+ onerror();
+ } else {
+ throw `Loading data file "${url}" failed.`;
+ }
+ });
+ if (dep) addRunDependency(dep);
+};
+
+var FS_createDataFile = (parent, name, fileData, canRead, canWrite, canOwn) => {
+ FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn);
+};
+
+var preloadPlugins = Module["preloadPlugins"] || [];
+
+var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => {
+ // Ensure plugins are ready.
+ if (typeof Browser != "undefined") Browser.init();
+ var handled = false;
+ preloadPlugins.forEach(plugin => {
+ if (handled) return;
+ if (plugin["canHandle"](fullname)) {
+ plugin["handle"](byteArray, fullname, finish, onerror);
+ handled = true;
+ }
+ });
+ return handled;
+};
+
+var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => {
+ // TODO we should allow people to just pass in a complete filename instead
+ // of parent and name being that we just join them anyways
+ var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent;
+ var dep = getUniqueRunDependency(`cp ${fullname}`);
+ // might have several active requests for the same fullname
+ function processData(byteArray) {
+ function finish(byteArray) {
+ preFinish?.();
+ if (!dontCreateFile) {
+ FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+ }
+ onload?.();
+ removeRunDependency(dep);
+ }
+ if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => {
+ onerror?.();
+ removeRunDependency(dep);
+ })) {
+ return;
+ }
+ finish(byteArray);
+ }
+ addRunDependency(dep);
+ if (typeof url == "string") {
+ asyncLoad(url, processData, onerror);
+ } else {
+ processData(url);
+ }
+};
+
+var FS_modeStringToFlags = str => {
+ var flagModes = {
+ "r": 0,
+ "r+": 2,
+ "w": 512 | 64 | 1,
+ "w+": 512 | 64 | 2,
+ "a": 1024 | 64 | 1,
+ "a+": 1024 | 64 | 2
+ };
+ var flags = flagModes[str];
+ if (typeof flags == "undefined") {
+ throw new Error(`Unknown file open mode: ${str}`);
+ }
+ return flags;
+};
+
+var FS_getMode = (canRead, canWrite) => {
+ var mode = 0;
+ if (canRead) mode |= 292 | 73;
+ if (canWrite) mode |= 146;
+ return mode;
+};
+
+var FS = {
+ root: null,
+ mounts: [],
+ devices: {},
+ streams: [],
+ nextInode: 1,
+ nameTable: null,
+ currentPath: "/",
+ initialized: false,
+ ignorePermissions: true,
+ ErrnoError: class {
+ name="ErrnoError";
+ // We set the `name` property to be able to identify `FS.ErrnoError`
+ // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway.
+ // - when using PROXYFS, an error can come from an underlying FS
+ // as different FS objects have their own FS.ErrnoError each,
+ // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs.
+ // we'll use the reliable test `err.name == "ErrnoError"` instead
+ constructor(errno) {
+ this.errno = errno;
+ }
+ },
+ filesystems: null,
+ syncFSRequests: 0,
+ readFiles: {},
+ FSStream: class {
+ shared={};
+ get object() {
+ return this.node;
+ }
+ set object(val) {
+ this.node = val;
+ }
+ get isRead() {
+ return (this.flags & 2097155) !== 1;
+ }
+ get isWrite() {
+ return (this.flags & 2097155) !== 0;
+ }
+ get isAppend() {
+ return (this.flags & 1024);
+ }
+ get flags() {
+ return this.shared.flags;
+ }
+ set flags(val) {
+ this.shared.flags = val;
+ }
+ get position() {
+ return this.shared.position;
+ }
+ set position(val) {
+ this.shared.position = val;
+ }
+ },
+ FSNode: class {
+ node_ops={};
+ stream_ops={};
+ readMode=292 | 73;
+ writeMode=146;
+ mounted=null;
+ constructor(parent, name, mode, rdev) {
+ if (!parent) {
+ parent = this;
+ }
+ // root node sets parent to itself
+ this.parent = parent;
+ this.mount = parent.mount;
+ this.id = FS.nextInode++;
+ this.name = name;
+ this.mode = mode;
+ this.rdev = rdev;
+ }
+ get read() {
+ return (this.mode & this.readMode) === this.readMode;
+ }
+ set read(val) {
+ val ? this.mode |= this.readMode : this.mode &= ~this.readMode;
+ }
+ get write() {
+ return (this.mode & this.writeMode) === this.writeMode;
+ }
+ set write(val) {
+ val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode;
+ }
+ get isFolder() {
+ return FS.isDir(this.mode);
+ }
+ get isDevice() {
+ return FS.isChrdev(this.mode);
+ }
+ },
+ lookupPath(path, opts = {}) {
+ path = PATH_FS.resolve(path);
+ if (!path) return {
+ path: "",
+ node: null
+ };
+ var defaults = {
+ follow_mount: true,
+ recurse_count: 0
+ };
+ opts = Object.assign(defaults, opts);
+ if (opts.recurse_count > 8) {
+ // max recursive lookup of 8
+ throw new FS.ErrnoError(32);
+ }
+ // split the absolute path
+ var parts = path.split("/").filter(p => !!p);
+ // start at the root
+ var current = FS.root;
+ var current_path = "/";
+ for (var i = 0; i < parts.length; i++) {
+ var islast = (i === parts.length - 1);
+ if (islast && opts.parent) {
+ // stop resolving
+ break;
+ }
+ current = FS.lookupNode(current, parts[i]);
+ current_path = PATH.join2(current_path, parts[i]);
+ // jump to the mount's root node if this is a mountpoint
+ if (FS.isMountpoint(current)) {
+ if (!islast || (islast && opts.follow_mount)) {
+ current = current.mounted.root;
+ }
+ }
+ // by default, lookupPath will not follow a symlink if it is the final path component.
+ // setting opts.follow = true will override this behavior.
+ if (!islast || opts.follow) {
+ var count = 0;
+ while (FS.isLink(current.mode)) {
+ var link = FS.readlink(current_path);
+ current_path = PATH_FS.resolve(PATH.dirname(current_path), link);
+ var lookup = FS.lookupPath(current_path, {
+ recurse_count: opts.recurse_count + 1
+ });
+ current = lookup.node;
+ if (count++ > 40) {
+ // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+ throw new FS.ErrnoError(32);
+ }
+ }
+ }
+ }
+ return {
+ path: current_path,
+ node: current
+ };
+ },
+ getPath(node) {
+ var path;
+ while (true) {
+ if (FS.isRoot(node)) {
+ var mount = node.mount.mountpoint;
+ if (!path) return mount;
+ return mount[mount.length - 1] !== "/" ? `${mount}/${path}` : mount + path;
+ }
+ path = path ? `${node.name}/${path}` : node.name;
+ node = node.parent;
+ }
+ },
+ hashName(parentid, name) {
+ var hash = 0;
+ for (var i = 0; i < name.length; i++) {
+ hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+ }
+ return ((parentid + hash) >>> 0) % FS.nameTable.length;
+ },
+ hashAddNode(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ node.name_next = FS.nameTable[hash];
+ FS.nameTable[hash] = node;
+ },
+ hashRemoveNode(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ if (FS.nameTable[hash] === node) {
+ FS.nameTable[hash] = node.name_next;
+ } else {
+ var current = FS.nameTable[hash];
+ while (current) {
+ if (current.name_next === node) {
+ current.name_next = node.name_next;
+ break;
+ }
+ current = current.name_next;
+ }
+ }
+ },
+ lookupNode(parent, name) {
+ var errCode = FS.mayLookup(parent);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ var hash = FS.hashName(parent.id, name);
+ for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+ var nodeName = node.name;
+ if (node.parent.id === parent.id && nodeName === name) {
+ return node;
+ }
+ }
+ // if we failed to find it in the cache, call into the VFS
+ return FS.lookup(parent, name);
+ },
+ createNode(parent, name, mode, rdev) {
+ var node = new FS.FSNode(parent, name, mode, rdev);
+ FS.hashAddNode(node);
+ return node;
+ },
+ destroyNode(node) {
+ FS.hashRemoveNode(node);
+ },
+ isRoot(node) {
+ return node === node.parent;
+ },
+ isMountpoint(node) {
+ return !!node.mounted;
+ },
+ isFile(mode) {
+ return (mode & 61440) === 32768;
+ },
+ isDir(mode) {
+ return (mode & 61440) === 16384;
+ },
+ isLink(mode) {
+ return (mode & 61440) === 40960;
+ },
+ isChrdev(mode) {
+ return (mode & 61440) === 8192;
+ },
+ isBlkdev(mode) {
+ return (mode & 61440) === 24576;
+ },
+ isFIFO(mode) {
+ return (mode & 61440) === 4096;
+ },
+ isSocket(mode) {
+ return (mode & 49152) === 49152;
+ },
+ flagsToPermissionString(flag) {
+ var perms = [ "r", "w", "rw" ][flag & 3];
+ if ((flag & 512)) {
+ perms += "w";
+ }
+ return perms;
+ },
+ nodePermissions(node, perms) {
+ if (FS.ignorePermissions) {
+ return 0;
+ }
+ // return 0 if any user, group or owner bits are set.
+ if (perms.includes("r") && !(node.mode & 292)) {
+ return 2;
+ } else if (perms.includes("w") && !(node.mode & 146)) {
+ return 2;
+ } else if (perms.includes("x") && !(node.mode & 73)) {
+ return 2;
+ }
+ return 0;
+ },
+ mayLookup(dir) {
+ if (!FS.isDir(dir.mode)) return 54;
+ var errCode = FS.nodePermissions(dir, "x");
+ if (errCode) return errCode;
+ if (!dir.node_ops.lookup) return 2;
+ return 0;
+ },
+ mayCreate(dir, name) {
+ try {
+ var node = FS.lookupNode(dir, name);
+ return 20;
+ } catch (e) {}
+ return FS.nodePermissions(dir, "wx");
+ },
+ mayDelete(dir, name, isdir) {
+ var node;
+ try {
+ node = FS.lookupNode(dir, name);
+ } catch (e) {
+ return e.errno;
+ }
+ var errCode = FS.nodePermissions(dir, "wx");
+ if (errCode) {
+ return errCode;
+ }
+ if (isdir) {
+ if (!FS.isDir(node.mode)) {
+ return 54;
+ }
+ if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+ return 10;
+ }
+ } else {
+ if (FS.isDir(node.mode)) {
+ return 31;
+ }
+ }
+ return 0;
+ },
+ mayOpen(node, flags) {
+ if (!node) {
+ return 44;
+ }
+ if (FS.isLink(node.mode)) {
+ return 32;
+ } else if (FS.isDir(node.mode)) {
+ if (FS.flagsToPermissionString(flags) !== "r" || // opening for write
+ (flags & 512)) {
+ // TODO: check for O_SEARCH? (== search for dir only)
+ return 31;
+ }
+ }
+ return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+ },
+ MAX_OPEN_FDS: 4096,
+ nextfd() {
+ for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) {
+ if (!FS.streams[fd]) {
+ return fd;
+ }
+ }
+ throw new FS.ErrnoError(33);
+ },
+ getStreamChecked(fd) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(8);
+ }
+ return stream;
+ },
+ getStream: fd => FS.streams[fd],
+ createStream(stream, fd = -1) {
+ // clone it, so we can return an instance of FSStream
+ stream = Object.assign(new FS.FSStream, stream);
+ if (fd == -1) {
+ fd = FS.nextfd();
+ }
+ stream.fd = fd;
+ FS.streams[fd] = stream;
+ return stream;
+ },
+ closeStream(fd) {
+ FS.streams[fd] = null;
+ },
+ dupStream(origStream, fd = -1) {
+ var stream = FS.createStream(origStream, fd);
+ stream.stream_ops?.dup?.(stream);
+ return stream;
+ },
+ chrdev_stream_ops: {
+ open(stream) {
+ var device = FS.getDevice(stream.node.rdev);
+ // override node's stream ops with the device's
+ stream.stream_ops = device.stream_ops;
+ // forward the open call
+ stream.stream_ops.open?.(stream);
+ },
+ llseek() {
+ throw new FS.ErrnoError(70);
+ }
+ },
+ major: dev => ((dev) >> 8),
+ minor: dev => ((dev) & 255),
+ makedev: (ma, mi) => ((ma) << 8 | (mi)),
+ registerDevice(dev, ops) {
+ FS.devices[dev] = {
+ stream_ops: ops
+ };
+ },
+ getDevice: dev => FS.devices[dev],
+ getMounts(mount) {
+ var mounts = [];
+ var check = [ mount ];
+ while (check.length) {
+ var m = check.pop();
+ mounts.push(m);
+ check.push(...m.mounts);
+ }
+ return mounts;
+ },
+ syncfs(populate, callback) {
+ if (typeof populate == "function") {
+ callback = populate;
+ populate = false;
+ }
+ FS.syncFSRequests++;
+ if (FS.syncFSRequests > 1) {
+ err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);
+ }
+ var mounts = FS.getMounts(FS.root.mount);
+ var completed = 0;
+ function doCallback(errCode) {
+ FS.syncFSRequests--;
+ return callback(errCode);
+ }
+ function done(errCode) {
+ if (errCode) {
+ if (!done.errored) {
+ done.errored = true;
+ return doCallback(errCode);
+ }
+ return;
+ }
+ if (++completed >= mounts.length) {
+ doCallback(null);
+ }
+ }
+ // sync all mounts
+ mounts.forEach(mount => {
+ if (!mount.type.syncfs) {
+ return done(null);
+ }
+ mount.type.syncfs(mount, populate, done);
+ });
+ },
+ mount(type, opts, mountpoint) {
+ var root = mountpoint === "/";
+ var pseudo = !mountpoint;
+ var node;
+ if (root && FS.root) {
+ throw new FS.ErrnoError(10);
+ } else if (!root && !pseudo) {
+ var lookup = FS.lookupPath(mountpoint, {
+ follow_mount: false
+ });
+ mountpoint = lookup.path;
+ // use the absolute path
+ node = lookup.node;
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ if (!FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ }
+ var mount = {
+ type,
+ opts,
+ mountpoint,
+ mounts: []
+ };
+ // create a root node for the fs
+ var mountRoot = type.mount(mount);
+ mountRoot.mount = mount;
+ mount.root = mountRoot;
+ if (root) {
+ FS.root = mountRoot;
+ } else if (node) {
+ // set as a mountpoint
+ node.mounted = mount;
+ // add the new mount to the current mount's children
+ if (node.mount) {
+ node.mount.mounts.push(mount);
+ }
+ }
+ return mountRoot;
+ },
+ unmount(mountpoint) {
+ var lookup = FS.lookupPath(mountpoint, {
+ follow_mount: false
+ });
+ if (!FS.isMountpoint(lookup.node)) {
+ throw new FS.ErrnoError(28);
+ }
+ // destroy the nodes for this mount, and all its child mounts
+ var node = lookup.node;
+ var mount = node.mounted;
+ var mounts = FS.getMounts(mount);
+ Object.keys(FS.nameTable).forEach(hash => {
+ var current = FS.nameTable[hash];
+ while (current) {
+ var next = current.name_next;
+ if (mounts.includes(current.mount)) {
+ FS.destroyNode(current);
+ }
+ current = next;
+ }
+ });
+ // no longer a mountpoint
+ node.mounted = null;
+ // remove this mount from the child mounts
+ var idx = node.mount.mounts.indexOf(mount);
+ node.mount.mounts.splice(idx, 1);
+ },
+ lookup(parent, name) {
+ return parent.node_ops.lookup(parent, name);
+ },
+ mknod(path, mode, dev) {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ if (!name || name === "." || name === "..") {
+ throw new FS.ErrnoError(28);
+ }
+ var errCode = FS.mayCreate(parent, name);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.mknod) {
+ throw new FS.ErrnoError(63);
+ }
+ return parent.node_ops.mknod(parent, name, mode, dev);
+ },
+ statfs(path) {
+ // NOTE: None of the defaults here are true. We're just returning safe and
+ // sane values.
+ var rtn = {
+ bsize: 4096,
+ frsize: 4096,
+ blocks: 1e6,
+ bfree: 5e5,
+ bavail: 5e5,
+ files: FS.nextInode,
+ ffree: FS.nextInode - 1,
+ fsid: 42,
+ flags: 2,
+ namelen: 255
+ };
+ var parent = FS.lookupPath(path, {
+ follow: true
+ }).node;
+ if (parent?.node_ops.statfs) {
+ Object.assign(rtn, parent.node_ops.statfs(parent.mount.opts.root));
+ }
+ return rtn;
+ },
+ create(path, mode = 438) {
+ mode &= 4095;
+ mode |= 32768;
+ return FS.mknod(path, mode, 0);
+ },
+ mkdir(path, mode = 511) {
+ mode &= 511 | 512;
+ mode |= 16384;
+ return FS.mknod(path, mode, 0);
+ },
+ mkdirTree(path, mode) {
+ var dirs = path.split("/");
+ var d = "";
+ for (var i = 0; i < dirs.length; ++i) {
+ if (!dirs[i]) continue;
+ d += "/" + dirs[i];
+ try {
+ FS.mkdir(d, mode);
+ } catch (e) {
+ if (e.errno != 20) throw e;
+ }
+ }
+ },
+ mkdev(path, mode, dev) {
+ if (typeof dev == "undefined") {
+ dev = mode;
+ mode = 438;
+ }
+ mode |= 8192;
+ return FS.mknod(path, mode, dev);
+ },
+ symlink(oldpath, newpath) {
+ if (!PATH_FS.resolve(oldpath)) {
+ throw new FS.ErrnoError(44);
+ }
+ var lookup = FS.lookupPath(newpath, {
+ parent: true
+ });
+ var parent = lookup.node;
+ if (!parent) {
+ throw new FS.ErrnoError(44);
+ }
+ var newname = PATH.basename(newpath);
+ var errCode = FS.mayCreate(parent, newname);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.symlink) {
+ throw new FS.ErrnoError(63);
+ }
+ return parent.node_ops.symlink(parent, newname, oldpath);
+ },
+ rename(old_path, new_path) {
+ var old_dirname = PATH.dirname(old_path);
+ var new_dirname = PATH.dirname(new_path);
+ var old_name = PATH.basename(old_path);
+ var new_name = PATH.basename(new_path);
+ // parents must exist
+ var lookup, old_dir, new_dir;
+ // let the errors from non existent directories percolate up
+ lookup = FS.lookupPath(old_path, {
+ parent: true
+ });
+ old_dir = lookup.node;
+ lookup = FS.lookupPath(new_path, {
+ parent: true
+ });
+ new_dir = lookup.node;
+ if (!old_dir || !new_dir) throw new FS.ErrnoError(44);
+ // need to be part of the same mount
+ if (old_dir.mount !== new_dir.mount) {
+ throw new FS.ErrnoError(75);
+ }
+ // source must exist
+ var old_node = FS.lookupNode(old_dir, old_name);
+ // old path should not be an ancestor of the new path
+ var relative = PATH_FS.relative(old_path, new_dirname);
+ if (relative.charAt(0) !== ".") {
+ throw new FS.ErrnoError(28);
+ }
+ // new path should not be an ancestor of the old path
+ relative = PATH_FS.relative(new_path, old_dirname);
+ if (relative.charAt(0) !== ".") {
+ throw new FS.ErrnoError(55);
+ }
+ // see if the new path already exists
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {}
+ // early out if nothing needs to change
+ if (old_node === new_node) {
+ return;
+ }
+ // we'll need to delete the old entry
+ var isdir = FS.isDir(old_node.mode);
+ var errCode = FS.mayDelete(old_dir, old_name, isdir);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ // need delete permissions if we'll be overwriting.
+ // need create permissions if new doesn't already exist.
+ errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!old_dir.node_ops.rename) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+ throw new FS.ErrnoError(10);
+ }
+ // if we are going to change the parent, check write permissions
+ if (new_dir !== old_dir) {
+ errCode = FS.nodePermissions(old_dir, "w");
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ }
+ // remove the node from the lookup hash
+ FS.hashRemoveNode(old_node);
+ // do the underlying fs rename
+ try {
+ old_dir.node_ops.rename(old_node, new_dir, new_name);
+ // update old node (we do this here to avoid each backend
+ // needing to)
+ old_node.parent = new_dir;
+ } catch (e) {
+ throw e;
+ } finally {
+ // add the node back to the hash (in case node_ops.rename
+ // changed its name)
+ FS.hashAddNode(old_node);
+ }
+ },
+ rmdir(path) {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var errCode = FS.mayDelete(parent, name, true);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.rmdir) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ parent.node_ops.rmdir(parent, name);
+ FS.destroyNode(node);
+ },
+ readdir(path) {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ var node = lookup.node;
+ if (!node.node_ops.readdir) {
+ throw new FS.ErrnoError(54);
+ }
+ return node.node_ops.readdir(node);
+ },
+ unlink(path) {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ var parent = lookup.node;
+ if (!parent) {
+ throw new FS.ErrnoError(44);
+ }
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var errCode = FS.mayDelete(parent, name, false);
+ if (errCode) {
+ // According to POSIX, we should map EISDIR to EPERM, but
+ // we instead do what Linux does (and we must, as we use
+ // the musl linux libc).
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.unlink) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ parent.node_ops.unlink(parent, name);
+ FS.destroyNode(node);
+ },
+ readlink(path) {
+ var lookup = FS.lookupPath(path);
+ var link = lookup.node;
+ if (!link) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!link.node_ops.readlink) {
+ throw new FS.ErrnoError(28);
+ }
+ return link.node_ops.readlink(link);
+ },
+ stat(path, dontFollow) {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontFollow
+ });
+ var node = lookup.node;
+ if (!node) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!node.node_ops.getattr) {
+ throw new FS.ErrnoError(63);
+ }
+ return node.node_ops.getattr(node);
+ },
+ lstat(path) {
+ return FS.stat(path, true);
+ },
+ chmod(path, mode, dontFollow) {
+ var node;
+ if (typeof path == "string") {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontFollow
+ });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ node.node_ops.setattr(node, {
+ mode: (mode & 4095) | (node.mode & ~4095),
+ timestamp: Date.now()
+ });
+ },
+ lchmod(path, mode) {
+ FS.chmod(path, mode, true);
+ },
+ fchmod(fd, mode) {
+ var stream = FS.getStreamChecked(fd);
+ FS.chmod(stream.node, mode);
+ },
+ chown(path, uid, gid, dontFollow) {
+ var node;
+ if (typeof path == "string") {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontFollow
+ });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ node.node_ops.setattr(node, {
+ timestamp: Date.now()
+ });
+ },
+ // we ignore the uid / gid for now
+ lchown(path, uid, gid) {
+ FS.chown(path, uid, gid, true);
+ },
+ fchown(fd, uid, gid) {
+ var stream = FS.getStreamChecked(fd);
+ FS.chown(stream.node, uid, gid);
+ },
+ truncate(path, len) {
+ if (len < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ var node;
+ if (typeof path == "string") {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!FS.isFile(node.mode)) {
+ throw new FS.ErrnoError(28);
+ }
+ var errCode = FS.nodePermissions(node, "w");
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ node.node_ops.setattr(node, {
+ size: len,
+ timestamp: Date.now()
+ });
+ },
+ ftruncate(fd, len) {
+ var stream = FS.getStreamChecked(fd);
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(28);
+ }
+ FS.truncate(stream.node, len);
+ },
+ utime(path, atime, mtime) {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ var node = lookup.node;
+ node.node_ops.setattr(node, {
+ timestamp: Math.max(atime, mtime)
+ });
+ },
+ open(path, flags, mode = 438) {
+ if (path === "") {
+ throw new FS.ErrnoError(44);
+ }
+ flags = typeof flags == "string" ? FS_modeStringToFlags(flags) : flags;
+ if ((flags & 64)) {
+ mode = (mode & 4095) | 32768;
+ } else {
+ mode = 0;
+ }
+ var node;
+ if (typeof path == "object") {
+ node = path;
+ } else {
+ path = PATH.normalize(path);
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & 131072)
+ });
+ node = lookup.node;
+ } catch (e) {}
+ }
+ // perhaps we need to create the node
+ var created = false;
+ if ((flags & 64)) {
+ if (node) {
+ // if O_CREAT and O_EXCL are set, error out if the node already exists
+ if ((flags & 128)) {
+ throw new FS.ErrnoError(20);
+ }
+ } else {
+ // node doesn't exist, try to create it
+ node = FS.mknod(path, mode, 0);
+ created = true;
+ }
+ }
+ if (!node) {
+ throw new FS.ErrnoError(44);
+ }
+ // can't truncate a device
+ if (FS.isChrdev(node.mode)) {
+ flags &= ~512;
+ }
+ // if asked only for a directory, then this must be one
+ if ((flags & 65536) && !FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ // check permissions, if this is not a file we just created now (it is ok to
+ // create and write to a file with read-only permissions; it is read-only
+ // for later use)
+ if (!created) {
+ var errCode = FS.mayOpen(node, flags);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ }
+ // do truncation if necessary
+ if ((flags & 512) && !created) {
+ FS.truncate(node, 0);
+ }
+ // we've already handled these, don't pass down to the underlying vfs
+ flags &= ~(128 | 512 | 131072);
+ // register the stream with the filesystem
+ var stream = FS.createStream({
+ node,
+ path: FS.getPath(node),
+ // we want the absolute path to the node
+ flags,
+ seekable: true,
+ position: 0,
+ stream_ops: node.stream_ops,
+ // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+ ungotten: [],
+ error: false
+ });
+ // call the new stream's open function
+ if (stream.stream_ops.open) {
+ stream.stream_ops.open(stream);
+ }
+ if (Module["logReadFiles"] && !(flags & 1)) {
+ if (!(path in FS.readFiles)) {
+ FS.readFiles[path] = 1;
+ }
+ }
+ return stream;
+ },
+ close(stream) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (stream.getdents) stream.getdents = null;
+ // free readdir state
+ try {
+ if (stream.stream_ops.close) {
+ stream.stream_ops.close(stream);
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ FS.closeStream(stream.fd);
+ }
+ stream.fd = null;
+ },
+ isClosed(stream) {
+ return stream.fd === null;
+ },
+ llseek(stream, offset, whence) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (!stream.seekable || !stream.stream_ops.llseek) {
+ throw new FS.ErrnoError(70);
+ }
+ if (whence != 0 && whence != 1 && whence != 2) {
+ throw new FS.ErrnoError(28);
+ }
+ stream.position = stream.stream_ops.llseek(stream, offset, whence);
+ stream.ungotten = [];
+ return stream.position;
+ },
+ read(stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if ((stream.flags & 2097155) === 1) {
+ throw new FS.ErrnoError(8);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!stream.stream_ops.read) {
+ throw new FS.ErrnoError(28);
+ }
+ var seeking = typeof position != "undefined";
+ if (!seeking) {
+ position = stream.position;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(70);
+ }
+ var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesRead;
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, position, canOwn) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(8);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!stream.stream_ops.write) {
+ throw new FS.ErrnoError(28);
+ }
+ if (stream.seekable && stream.flags & 1024) {
+ // seek to the end before writing in append mode
+ FS.llseek(stream, 0, 2);
+ }
+ var seeking = typeof position != "undefined";
+ if (!seeking) {
+ position = stream.position;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(70);
+ }
+ var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+ if (!seeking) stream.position += bytesWritten;
+ return bytesWritten;
+ },
+ allocate(stream, offset, length) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (offset < 0 || length <= 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(8);
+ }
+ if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ if (!stream.stream_ops.allocate) {
+ throw new FS.ErrnoError(138);
+ }
+ stream.stream_ops.allocate(stream, offset, length);
+ },
+ mmap(stream, length, position, prot, flags) {
+ // User requests writing to file (prot & PROT_WRITE != 0).
+ // Checking if we have permissions to write to the file unless
+ // MAP_PRIVATE flag is set. According to POSIX spec it is possible
+ // to write to file opened in read-only mode with MAP_PRIVATE flag,
+ // as all modifications will be visible only in the memory of
+ // the current process.
+ if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) {
+ throw new FS.ErrnoError(2);
+ }
+ if ((stream.flags & 2097155) === 1) {
+ throw new FS.ErrnoError(2);
+ }
+ if (!stream.stream_ops.mmap) {
+ throw new FS.ErrnoError(43);
+ }
+ if (!length) {
+ throw new FS.ErrnoError(28);
+ }
+ return stream.stream_ops.mmap(stream, length, position, prot, flags);
+ },
+ msync(stream, buffer, offset, length, mmapFlags) {
+ if (!stream.stream_ops.msync) {
+ return 0;
+ }
+ return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);
+ },
+ ioctl(stream, cmd, arg) {
+ if (!stream.stream_ops.ioctl) {
+ throw new FS.ErrnoError(59);
+ }
+ return stream.stream_ops.ioctl(stream, cmd, arg);
+ },
+ readFile(path, opts = {}) {
+ opts.flags = opts.flags || 0;
+ opts.encoding = opts.encoding || "binary";
+ if (opts.encoding !== "utf8" && opts.encoding !== "binary") {
+ throw new Error(`Invalid encoding type "${opts.encoding}"`);
+ }
+ var ret;
+ var stream = FS.open(path, opts.flags);
+ var stat = FS.stat(path);
+ var length = stat.size;
+ var buf = new Uint8Array(length);
+ FS.read(stream, buf, 0, length, 0);
+ if (opts.encoding === "utf8") {
+ ret = UTF8ArrayToString(buf);
+ } else if (opts.encoding === "binary") {
+ ret = buf;
+ }
+ FS.close(stream);
+ return ret;
+ },
+ writeFile(path, data, opts = {}) {
+ opts.flags = opts.flags || 577;
+ var stream = FS.open(path, opts.flags, opts.mode);
+ if (typeof data == "string") {
+ var buf = new Uint8Array(lengthBytesUTF8(data) + 1);
+ var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);
+ FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn);
+ } else if (ArrayBuffer.isView(data)) {
+ FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
+ } else {
+ throw new Error("Unsupported data type");
+ }
+ FS.close(stream);
+ },
+ cwd: () => FS.currentPath,
+ chdir(path) {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ if (lookup.node === null) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!FS.isDir(lookup.node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ var errCode = FS.nodePermissions(lookup.node, "x");
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ FS.currentPath = lookup.path;
+ },
+ createDefaultDirectories() {
+ FS.mkdir("/tmp");
+ FS.mkdir("/home");
+ FS.mkdir("/home/web_user");
+ },
+ createDefaultDevices() {
+ // create /dev
+ FS.mkdir("/dev");
+ // setup /dev/null
+ FS.registerDevice(FS.makedev(1, 3), {
+ read: () => 0,
+ write: (stream, buffer, offset, length, pos) => length,
+ llseek: () => 0
+ });
+ FS.mkdev("/dev/null", FS.makedev(1, 3));
+ // setup /dev/tty and /dev/tty1
+ // stderr needs to print output using err() rather than out()
+ // so we register a second tty just for it.
+ TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+ TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+ FS.mkdev("/dev/tty", FS.makedev(5, 0));
+ FS.mkdev("/dev/tty1", FS.makedev(6, 0));
+ // setup /dev/[u]random
+ // use a buffer to avoid overhead of individual crypto calls per byte
+ var randomBuffer = new Uint8Array(1024), randomLeft = 0;
+ var randomByte = () => {
+ if (randomLeft === 0) {
+ randomLeft = randomFill(randomBuffer).byteLength;
+ }
+ return randomBuffer[--randomLeft];
+ };
+ FS.createDevice("/dev", "random", randomByte);
+ FS.createDevice("/dev", "urandom", randomByte);
+ // we're not going to emulate the actual shm device,
+ // just create the tmp dirs that reside in it commonly
+ FS.mkdir("/dev/shm");
+ FS.mkdir("/dev/shm/tmp");
+ },
+ createSpecialDirectories() {
+ // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the
+ // name of the stream for fd 6 (see test_unistd_ttyname)
+ FS.mkdir("/proc");
+ var proc_self = FS.mkdir("/proc/self");
+ FS.mkdir("/proc/self/fd");
+ FS.mount({
+ mount() {
+ var node = FS.createNode(proc_self, "fd", 16895, 73);
+ node.node_ops = {
+ lookup(parent, name) {
+ var fd = +name;
+ var stream = FS.getStreamChecked(fd);
+ var ret = {
+ parent: null,
+ mount: {
+ mountpoint: "fake"
+ },
+ node_ops: {
+ readlink: () => stream.path
+ }
+ };
+ ret.parent = ret;
+ // make it look like a simple root node
+ return ret;
+ }
+ };
+ return node;
+ }
+ }, {}, "/proc/self/fd");
+ },
+ createStandardStreams(input, output, error) {
+ // TODO deprecate the old functionality of a single
+ // input / output callback and that utilizes FS.createDevice
+ // and instead require a unique set of stream ops
+ // by default, we symlink the standard streams to the
+ // default tty devices. however, if the standard streams
+ // have been overwritten we create a unique device for
+ // them instead.
+ if (input) {
+ FS.createDevice("/dev", "stdin", input);
+ } else {
+ FS.symlink("/dev/tty", "/dev/stdin");
+ }
+ if (output) {
+ FS.createDevice("/dev", "stdout", null, output);
+ } else {
+ FS.symlink("/dev/tty", "/dev/stdout");
+ }
+ if (error) {
+ FS.createDevice("/dev", "stderr", null, error);
+ } else {
+ FS.symlink("/dev/tty1", "/dev/stderr");
+ }
+ // open default streams for the stdin, stdout and stderr devices
+ var stdin = FS.open("/dev/stdin", 0);
+ var stdout = FS.open("/dev/stdout", 1);
+ var stderr = FS.open("/dev/stderr", 1);
+ },
+ staticInit() {
+ FS.nameTable = new Array(4096);
+ FS.mount(MEMFS, {}, "/");
+ FS.createDefaultDirectories();
+ FS.createDefaultDevices();
+ FS.createSpecialDirectories();
+ FS.filesystems = {
+ "MEMFS": MEMFS
+ };
+ },
+ init(input, output, error) {
+ FS.initialized = true;
+ // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+ input ??= Module["stdin"];
+ output ??= Module["stdout"];
+ error ??= Module["stderr"];
+ FS.createStandardStreams(input, output, error);
+ },
+ quit() {
+ FS.initialized = false;
+ // force-flush all streams, so we get musl std streams printed out
+ // close all of our streams
+ for (var i = 0; i < FS.streams.length; i++) {
+ var stream = FS.streams[i];
+ if (!stream) {
+ continue;
+ }
+ FS.close(stream);
+ }
+ },
+ findObject(path, dontResolveLastLink) {
+ var ret = FS.analyzePath(path, dontResolveLastLink);
+ if (!ret.exists) {
+ return null;
+ }
+ return ret.object;
+ },
+ analyzePath(path, dontResolveLastLink) {
+ // operate from within the context of the symlink's target
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontResolveLastLink
+ });
+ path = lookup.path;
+ } catch (e) {}
+ var ret = {
+ isRoot: false,
+ exists: false,
+ error: 0,
+ name: null,
+ path: null,
+ object: null,
+ parentExists: false,
+ parentPath: null,
+ parentObject: null
+ };
+ try {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ ret.parentExists = true;
+ ret.parentPath = lookup.path;
+ ret.parentObject = lookup.node;
+ ret.name = PATH.basename(path);
+ lookup = FS.lookupPath(path, {
+ follow: !dontResolveLastLink
+ });
+ ret.exists = true;
+ ret.path = lookup.path;
+ ret.object = lookup.node;
+ ret.name = lookup.node.name;
+ ret.isRoot = lookup.path === "/";
+ } catch (e) {
+ ret.error = e.errno;
+ }
+ return ret;
+ },
+ createPath(parent, path, canRead, canWrite) {
+ parent = typeof parent == "string" ? parent : FS.getPath(parent);
+ var parts = path.split("/").reverse();
+ while (parts.length) {
+ var part = parts.pop();
+ if (!part) continue;
+ var current = PATH.join2(parent, part);
+ try {
+ FS.mkdir(current);
+ } catch (e) {}
+ // ignore EEXIST
+ parent = current;
+ }
+ return current;
+ },
+ createFile(parent, name, properties, canRead, canWrite) {
+ var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
+ var mode = FS_getMode(canRead, canWrite);
+ return FS.create(path, mode);
+ },
+ createDataFile(parent, name, data, canRead, canWrite, canOwn) {
+ var path = name;
+ if (parent) {
+ parent = typeof parent == "string" ? parent : FS.getPath(parent);
+ path = name ? PATH.join2(parent, name) : parent;
+ }
+ var mode = FS_getMode(canRead, canWrite);
+ var node = FS.create(path, mode);
+ if (data) {
+ if (typeof data == "string") {
+ var arr = new Array(data.length);
+ for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+ data = arr;
+ }
+ // make sure we can write to the file
+ FS.chmod(node, mode | 146);
+ var stream = FS.open(node, 577);
+ FS.write(stream, data, 0, data.length, 0, canOwn);
+ FS.close(stream);
+ FS.chmod(node, mode);
+ }
+ },
+ createDevice(parent, name, input, output) {
+ var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
+ var mode = FS_getMode(!!input, !!output);
+ FS.createDevice.major ??= 64;
+ var dev = FS.makedev(FS.createDevice.major++, 0);
+ // Create a fake device that a set of stream ops to emulate
+ // the old behavior.
+ FS.registerDevice(dev, {
+ open(stream) {
+ stream.seekable = false;
+ },
+ close(stream) {
+ // flush any pending line data
+ if (output?.buffer?.length) {
+ output(10);
+ }
+ },
+ read(stream, buffer, offset, length, pos) {
+ /* ignored */ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = input();
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(6);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset + i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, pos) {
+ for (var i = 0; i < length; i++) {
+ try {
+ output(buffer[offset + i]);
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ });
+ return FS.mkdev(path, mode, dev);
+ },
+ forceLoadFile(obj) {
+ if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+ if (typeof XMLHttpRequest != "undefined") {
+ throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+ } else {
+ // Command-line.
+ try {
+ obj.contents = readBinary(obj.url);
+ obj.usedBytes = obj.contents.length;
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ }
+ },
+ createLazyFile(parent, name, url, canRead, canWrite) {
+ // Lazy chunked Uint8Array (implements get and length from Uint8Array).
+ // Actual getting is abstracted away for eventual reuse.
+ class LazyUint8Array {
+ lengthKnown=false;
+ chunks=[];
+ // Loaded chunks. Index is the chunk number
+ get(idx) {
+ if (idx > this.length - 1 || idx < 0) {
+ return undefined;
+ }
+ var chunkOffset = idx % this.chunkSize;
+ var chunkNum = (idx / this.chunkSize) | 0;
+ return this.getter(chunkNum)[chunkOffset];
+ }
+ setDataGetter(getter) {
+ this.getter = getter;
+ }
+ cacheLength() {
+ // Find length
+ var xhr = new XMLHttpRequest;
+ xhr.open("HEAD", url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+ var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
+ var chunkSize = 1024 * 1024;
+ // Chunk size in bytes
+ if (!hasByteServing) chunkSize = datalength;
+ // Function to get a range from the remote URL.
+ var doXHR = (from, to) => {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength - 1) throw new Error("only " + datalength + " bytes available! programmer error!");
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+ // Some hints to the browser that we want binary data.
+ xhr.responseType = "arraybuffer";
+ if (xhr.overrideMimeType) {
+ xhr.overrideMimeType("text/plain; charset=x-user-defined");
+ }
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ if (xhr.response !== undefined) {
+ return new Uint8Array(/** @type{Array<number>} */ (xhr.response || []));
+ }
+ return intArrayFromString(xhr.responseText || "", true);
+ };
+ var lazyArray = this;
+ lazyArray.setDataGetter(chunkNum => {
+ var start = chunkNum * chunkSize;
+ var end = (chunkNum + 1) * chunkSize - 1;
+ // including this byte
+ end = Math.min(end, datalength - 1);
+ // if datalength-1 is selected, this is the last block
+ if (typeof lazyArray.chunks[chunkNum] == "undefined") {
+ lazyArray.chunks[chunkNum] = doXHR(start, end);
+ }
+ if (typeof lazyArray.chunks[chunkNum] == "undefined") throw new Error("doXHR failed!");
+ return lazyArray.chunks[chunkNum];
+ });
+ if (usesGzip || !datalength) {
+ // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length
+ chunkSize = datalength = 1;
+ // this will force getter(0)/doXHR do download the whole file
+ datalength = this.getter(0).length;
+ chunkSize = datalength;
+ out("LazyFiles on gzip forces download of the whole file when length is accessed");
+ }
+ this._length = datalength;
+ this._chunkSize = chunkSize;
+ this.lengthKnown = true;
+ }
+ get length() {
+ if (!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._length;
+ }
+ get chunkSize() {
+ if (!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._chunkSize;
+ }
+ }
+ if (typeof XMLHttpRequest != "undefined") {
+ if (!ENVIRONMENT_IS_WORKER) throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";
+ var lazyArray = new LazyUint8Array;
+ var properties = {
+ isDevice: false,
+ contents: lazyArray
+ };
+ } else {
+ var properties = {
+ isDevice: false,
+ url
+ };
+ }
+ var node = FS.createFile(parent, name, properties, canRead, canWrite);
+ // This is a total hack, but I want to get this lazy file code out of the
+ // core of MEMFS. If we want to keep this lazy file concept I feel it should
+ // be its own thin LAZYFS proxying calls to MEMFS.
+ if (properties.contents) {
+ node.contents = properties.contents;
+ } else if (properties.url) {
+ node.contents = null;
+ node.url = properties.url;
+ }
+ // Add a function that defers querying the file size until it is asked the first time.
+ Object.defineProperties(node, {
+ usedBytes: {
+ get: function() {
+ return this.contents.length;
+ }
+ }
+ });
+ // override each stream op with one that tries to force load the lazy file first
+ var stream_ops = {};
+ var keys = Object.keys(node.stream_ops);
+ keys.forEach(key => {
+ var fn = node.stream_ops[key];
+ stream_ops[key] = (...args) => {
+ FS.forceLoadFile(node);
+ return fn(...args);
+ };
+ });
+ function writeChunks(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ if (position >= contents.length) return 0;
+ var size = Math.min(contents.length - position, length);
+ if (contents.slice) {
+ // normal array
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ } else {
+ for (var i = 0; i < size; i++) {
+ // LazyUint8Array from sync binary XHR
+ buffer[offset + i] = contents.get(position + i);
+ }
+ }
+ return size;
+ }
+ // use a custom read function
+ stream_ops.read = (stream, buffer, offset, length, position) => {
+ FS.forceLoadFile(node);
+ return writeChunks(stream, buffer, offset, length, position);
+ };
+ // use a custom mmap function
+ stream_ops.mmap = (stream, length, position, prot, flags) => {
+ FS.forceLoadFile(node);
+ var ptr = mmapAlloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(48);
+ }
+ writeChunks(stream, HEAP8, ptr, length, position);
+ return {
+ ptr,
+ allocated: true
+ };
+ };
+ node.stream_ops = stream_ops;
+ return node;
+ }
+};
+
+/**
+ * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the
+ * emscripten HEAP, returns a copy of that string as a Javascript String object.
+ *
+ * @param {number} ptr
+ * @param {number=} maxBytesToRead - An optional length that specifies the
+ * maximum number of bytes to read. You can omit this parameter to scan the
+ * string until the first 0 byte. If maxBytesToRead is passed, and the string
+ * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the
+ * string will cut short at that byte index (i.e. maxBytesToRead will not
+ * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing
+ * frequent uses of UTF8ToString() with and without maxBytesToRead may throw
+ * JS JIT optimizations off, so it is worth to consider consistently using one
+ * @return {string}
+ */ var UTF8ToString = (ptr, maxBytesToRead) => ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : "";
+
+var SYSCALLS = {
+ DEFAULT_POLLMASK: 5,
+ calculateAt(dirfd, path, allowEmpty) {
+ if (PATH.isAbs(path)) {
+ return path;
+ }
+ // relative path
+ var dir;
+ if (dirfd === -100) {
+ dir = FS.cwd();
+ } else {
+ var dirstream = SYSCALLS.getStreamFromFD(dirfd);
+ dir = dirstream.path;
+ }
+ if (path.length == 0) {
+ if (!allowEmpty) {
+ throw new FS.ErrnoError(44);
+ }
+ return dir;
+ }
+ return PATH.join2(dir, path);
+ },
+ doStat(func, path, buf) {
+ var stat = func(path);
+ HEAP32[((buf) >> 2)] = stat.dev;
+ HEAP32[(((buf) + (4)) >> 2)] = stat.mode;
+ HEAPU32[(((buf) + (8)) >> 2)] = stat.nlink;
+ HEAP32[(((buf) + (12)) >> 2)] = stat.uid;
+ HEAP32[(((buf) + (16)) >> 2)] = stat.gid;
+ HEAP32[(((buf) + (20)) >> 2)] = stat.rdev;
+ (tempI64 = [ stat.size >>> 0, (tempDouble = stat.size, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (24)) >> 2)] = tempI64[0], HEAP32[(((buf) + (28)) >> 2)] = tempI64[1]);
+ HEAP32[(((buf) + (32)) >> 2)] = 4096;
+ HEAP32[(((buf) + (36)) >> 2)] = stat.blocks;
+ var atime = stat.atime.getTime();
+ var mtime = stat.mtime.getTime();
+ var ctime = stat.ctime.getTime();
+ (tempI64 = [ Math.floor(atime / 1e3) >>> 0, (tempDouble = Math.floor(atime / 1e3),
+ (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (40)) >> 2)] = tempI64[0], HEAP32[(((buf) + (44)) >> 2)] = tempI64[1]);
+ HEAPU32[(((buf) + (48)) >> 2)] = (atime % 1e3) * 1e3 * 1e3;
+ (tempI64 = [ Math.floor(mtime / 1e3) >>> 0, (tempDouble = Math.floor(mtime / 1e3),
+ (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (56)) >> 2)] = tempI64[0], HEAP32[(((buf) + (60)) >> 2)] = tempI64[1]);
+ HEAPU32[(((buf) + (64)) >> 2)] = (mtime % 1e3) * 1e3 * 1e3;
+ (tempI64 = [ Math.floor(ctime / 1e3) >>> 0, (tempDouble = Math.floor(ctime / 1e3),
+ (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (72)) >> 2)] = tempI64[0], HEAP32[(((buf) + (76)) >> 2)] = tempI64[1]);
+ HEAPU32[(((buf) + (80)) >> 2)] = (ctime % 1e3) * 1e3 * 1e3;
+ (tempI64 = [ stat.ino >>> 0, (tempDouble = stat.ino, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (88)) >> 2)] = tempI64[0], HEAP32[(((buf) + (92)) >> 2)] = tempI64[1]);
+ return 0;
+ },
+ doMsync(addr, stream, len, flags, offset) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ if (flags & 2) {
+ // MAP_PRIVATE calls need not to be synced back to underlying fs
+ return 0;
+ }
+ var buffer = HEAPU8.slice(addr, addr + len);
+ FS.msync(stream, buffer, offset, len, flags);
+ },
+ getStreamFromFD(fd) {
+ var stream = FS.getStreamChecked(fd);
+ return stream;
+ },
+ varargs: undefined,
+ getStr(ptr) {
+ var ret = UTF8ToString(ptr);
+ return ret;
+ }
+};
+
+function ___syscall_fcntl64(fd, cmd, varargs) {
+ SYSCALLS.varargs = varargs;
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ switch (cmd) {
+ case 0:
+ {
+ var arg = syscallGetVarargI();
+ if (arg < 0) {
+ return -28;
+ }
+ while (FS.streams[arg]) {
+ arg++;
+ }
+ var newStream;
+ newStream = FS.dupStream(stream, arg);
+ return newStream.fd;
+ }
+
+ case 1:
+ case 2:
+ return 0;
+
+ // FD_CLOEXEC makes no sense for a single process.
+ case 3:
+ return stream.flags;
+
+ case 4:
+ {
+ var arg = syscallGetVarargI();
+ stream.flags |= arg;
+ return 0;
+ }
+
+ case 12:
+ {
+ var arg = syscallGetVarargP();
+ var offset = 0;
+ // We're always unlocked.
+ HEAP16[(((arg) + (offset)) >> 1)] = 2;
+ return 0;
+ }
+
+ case 13:
+ case 14:
+ return 0;
+ }
+ // Pretend that the locking is successful.
+ return -28;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return -e.errno;
+ }
+}
+
+function ___syscall_ioctl(fd, op, varargs) {
+ SYSCALLS.varargs = varargs;
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ switch (op) {
+ case 21509:
+ {
+ if (!stream.tty) return -59;
+ return 0;
+ }
+
+ case 21505:
+ {
+ if (!stream.tty) return -59;
+ if (stream.tty.ops.ioctl_tcgets) {
+ var termios = stream.tty.ops.ioctl_tcgets(stream);
+ var argp = syscallGetVarargP();
+ HEAP32[((argp) >> 2)] = termios.c_iflag || 0;
+ HEAP32[(((argp) + (4)) >> 2)] = termios.c_oflag || 0;
+ HEAP32[(((argp) + (8)) >> 2)] = termios.c_cflag || 0;
+ HEAP32[(((argp) + (12)) >> 2)] = termios.c_lflag || 0;
+ for (var i = 0; i < 32; i++) {
+ HEAP8[(argp + i) + (17)] = termios.c_cc[i] || 0;
+ }
+ return 0;
+ }
+ return 0;
+ }
+
+ case 21510:
+ case 21511:
+ case 21512:
+ {
+ if (!stream.tty) return -59;
+ return 0;
+ }
+
+ // no-op, not actually adjusting terminal settings
+ case 21506:
+ case 21507:
+ case 21508:
+ {
+ if (!stream.tty) return -59;
+ if (stream.tty.ops.ioctl_tcsets) {
+ var argp = syscallGetVarargP();
+ var c_iflag = HEAP32[((argp) >> 2)];
+ var c_oflag = HEAP32[(((argp) + (4)) >> 2)];
+ var c_cflag = HEAP32[(((argp) + (8)) >> 2)];
+ var c_lflag = HEAP32[(((argp) + (12)) >> 2)];
+ var c_cc = [];
+ for (var i = 0; i < 32; i++) {
+ c_cc.push(HEAP8[(argp + i) + (17)]);
+ }
+ return stream.tty.ops.ioctl_tcsets(stream.tty, op, {
+ c_iflag,
+ c_oflag,
+ c_cflag,
+ c_lflag,
+ c_cc
+ });
+ }
+ return 0;
+ }
+
+ // no-op, not actually adjusting terminal settings
+ case 21519:
+ {
+ if (!stream.tty) return -59;
+ var argp = syscallGetVarargP();
+ HEAP32[((argp) >> 2)] = 0;
+ return 0;
+ }
+
+ case 21520:
+ {
+ if (!stream.tty) return -59;
+ return -28;
+ }
+
+ // not supported
+ case 21531:
+ {
+ var argp = syscallGetVarargP();
+ return FS.ioctl(stream, op, argp);
+ }
+
+ case 21523:
+ {
+ // TODO: in theory we should write to the winsize struct that gets
+ // passed in, but for now musl doesn't read anything on it
+ if (!stream.tty) return -59;
+ if (stream.tty.ops.ioctl_tiocgwinsz) {
+ var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
+ var argp = syscallGetVarargP();
+ HEAP16[((argp) >> 1)] = winsize[0];
+ HEAP16[(((argp) + (2)) >> 1)] = winsize[1];
+ }
+ return 0;
+ }
+
+ case 21524:
+ {
+ // TODO: technically, this ioctl call should change the window size.
+ // but, since emscripten doesn't have any concept of a terminal window
+ // yet, we'll just silently throw it away as we do TIOCGWINSZ
+ if (!stream.tty) return -59;
+ return 0;
+ }
+
+ case 21515:
+ {
+ if (!stream.tty) return -59;
+ return 0;
+ }
+
+ default:
+ return -28;
+ }
+ } // not supported
+ catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return -e.errno;
+ }
+}
+
+function ___syscall_openat(dirfd, path, flags, varargs) {
+ SYSCALLS.varargs = varargs;
+ try {
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ var mode = varargs ? syscallGetVarargI() : 0;
+ return FS.open(path, flags, mode).fd;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return -e.errno;
+ }
+}
+
+function ___syscall_unlinkat(dirfd, path, flags) {
+ try {
+ path = SYSCALLS.getStr(path);
+ path = SYSCALLS.calculateAt(dirfd, path);
+ if (flags === 0) {
+ FS.unlink(path);
+ } else if (flags === 512) {
+ FS.rmdir(path);
+ } else {
+ abort("Invalid flags passed to unlinkat");
+ }
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return -e.errno;
+ }
+}
+
+var __abort_js = () => abort("");
+
+var __emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num);
+
+var _emscripten_date_now = () => Date.now();
+
+var abortOnCannotGrowMemory = requestedSize => {
+ abort("OOM");
+};
+
+var _emscripten_resize_heap = requestedSize => {
+ var oldSize = HEAPU8.length;
+ // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
+ requestedSize >>>= 0;
+ abortOnCannotGrowMemory(requestedSize);
+};
+
+var ENV = {};
+
+var getExecutableName = () => thisProgram || "./this.program";
+
+var getEnvStrings = () => {
+ if (!getEnvStrings.strings) {
+ // Default values.
+ // Browser language detection #8751
+ var lang = ((typeof navigator == "object" && navigator.languages && navigator.languages[0]) || "C").replace("-", "_") + ".UTF-8";
+ var env = {
+ "USER": "web_user",
+ "LOGNAME": "web_user",
+ "PATH": "/",
+ "PWD": "/",
+ "HOME": "/home/web_user",
+ "LANG": lang,
+ "_": getExecutableName()
+ };
+ // Apply the user-provided values, if any.
+ for (var x in ENV) {
+ // x is a key in ENV; if ENV[x] is undefined, that means it was
+ // explicitly set to be so. We allow user code to do that to
+ // force variables with default values to remain unset.
+ if (ENV[x] === undefined) delete env[x]; else env[x] = ENV[x];
+ }
+ var strings = [];
+ for (var x in env) {
+ strings.push(`${x}=${env[x]}`);
+ }
+ getEnvStrings.strings = strings;
+ }
+ return getEnvStrings.strings;
+};
+
+var stringToAscii = (str, buffer) => {
+ for (var i = 0; i < str.length; ++i) {
+ HEAP8[buffer++] = str.charCodeAt(i);
+ }
+ // Null-terminate the string
+ HEAP8[buffer] = 0;
+};
+
+var _environ_get = (__environ, environ_buf) => {
+ var bufSize = 0;
+ getEnvStrings().forEach((string, i) => {
+ var ptr = environ_buf + bufSize;
+ HEAPU32[(((__environ) + (i * 4)) >> 2)] = ptr;
+ stringToAscii(string, ptr);
+ bufSize += string.length + 1;
+ });
+ return 0;
+};
+
+var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
+ var strings = getEnvStrings();
+ HEAPU32[((penviron_count) >> 2)] = strings.length;
+ var bufSize = 0;
+ strings.forEach(string => bufSize += string.length + 1);
+ HEAPU32[((penviron_buf_size) >> 2)] = bufSize;
+ return 0;
+};
+
+var runtimeKeepaliveCounter = 0;
+
+var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
+
+var _proc_exit = code => {
+ EXITSTATUS = code;
+ if (!keepRuntimeAlive()) {
+ Module["onExit"]?.(code);
+ ABORT = true;
+ }
+ quit_(code, new ExitStatus(code));
+};
+
+/** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => {
+ EXITSTATUS = status;
+ _proc_exit(status);
+};
+
+var _exit = exitJS;
+
+function _fd_close(fd) {
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ FS.close(stream);
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+/** @param {number=} offset */ var doReadv = (stream, iov, iovcnt, offset) => {
+ var ret = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[((iov) >> 2)];
+ var len = HEAPU32[(((iov) + (4)) >> 2)];
+ iov += 8;
+ var curr = FS.read(stream, HEAP8, ptr, len, offset);
+ if (curr < 0) return -1;
+ ret += curr;
+ if (curr < len) break;
+ // nothing more to read
+ if (typeof offset != "undefined") {
+ offset += curr;
+ }
+ }
+ return ret;
+};
+
+function _fd_read(fd, iov, iovcnt, pnum) {
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var num = doReadv(stream, iov, iovcnt);
+ HEAPU32[((pnum) >> 2)] = num;
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+var convertI32PairToI53Checked = (lo, hi) => ((hi + 2097152) >>> 0 < 4194305 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN;
+
+function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
+ var offset = convertI32PairToI53Checked(offset_low, offset_high);
+ try {
+ if (isNaN(offset)) return 61;
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ FS.llseek(stream, offset, whence);
+ (tempI64 = [ stream.position >>> 0, (tempDouble = stream.position, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[((newOffset) >> 2)] = tempI64[0], HEAP32[(((newOffset) + (4)) >> 2)] = tempI64[1]);
+ if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null;
+ // reset readdir state
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+/** @param {number=} offset */ var doWritev = (stream, iov, iovcnt, offset) => {
+ var ret = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[((iov) >> 2)];
+ var len = HEAPU32[(((iov) + (4)) >> 2)];
+ iov += 8;
+ var curr = FS.write(stream, HEAP8, ptr, len, offset);
+ if (curr < 0) return -1;
+ ret += curr;
+ if (curr < len) {
+ // No more space to write.
+ break;
+ }
+ if (typeof offset != "undefined") {
+ offset += curr;
+ }
+ }
+ return ret;
+};
+
+function _fd_write(fd, iov, iovcnt, pnum) {
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var num = doWritev(stream, iov, iovcnt);
+ HEAPU32[((pnum) >> 2)] = num;
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+FS.createPreloadedFile = FS_createPreloadedFile;
+
+FS.staticInit();
+
+// This error may happen quite a bit. To avoid overhead we reuse it (and
+// suffer a lack of stack info).
+MEMFS.doesNotExistError = new FS.ErrnoError(44);
+
+/** @suppress {checkTypes} */ MEMFS.doesNotExistError.stack = "<generic error, no stack>";
+
+var wasmImports = {
+ /** @export */ __syscall_fcntl64: ___syscall_fcntl64,
+ /** @export */ __syscall_ioctl: ___syscall_ioctl,
+ /** @export */ __syscall_openat: ___syscall_openat,
+ /** @export */ __syscall_unlinkat: ___syscall_unlinkat,
+ /** @export */ _abort_js: __abort_js,
+ /** @export */ _emscripten_memcpy_js: __emscripten_memcpy_js,
+ /** @export */ emscripten_date_now: _emscripten_date_now,
+ /** @export */ emscripten_resize_heap: _emscripten_resize_heap,
+ /** @export */ environ_get: _environ_get,
+ /** @export */ environ_sizes_get: _environ_sizes_get,
+ /** @export */ exit: _exit,
+ /** @export */ fd_close: _fd_close,
+ /** @export */ fd_read: _fd_read,
+ /** @export */ fd_seek: _fd_seek,
+ /** @export */ fd_write: _fd_write
+};
+
+var wasmExports = createWasm();
+
+var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["__wasm_call_ctors"])();
+
+var _runIteration = Module["_runIteration"] = a0 => (_runIteration = Module["_runIteration"] = wasmExports["runIteration"])(a0);
+
+var __emscripten_stack_restore = a0 => (__emscripten_stack_restore = wasmExports["_emscripten_stack_restore"])(a0);
+
+var __emscripten_stack_alloc = a0 => (__emscripten_stack_alloc = wasmExports["_emscripten_stack_alloc"])(a0);
+
+var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports["emscripten_stack_get_current"])();
+
+var dynCall_jiji = Module["dynCall_jiji"] = (a0, a1, a2, a3, a4) => (dynCall_jiji = Module["dynCall_jiji"] = wasmExports["dynCall_jiji"])(a0, a1, a2, a3, a4);
+
+// include: postamble.js
+// === Auto-generated postamble setup entry stuff ===
+var calledRun;
+
+dependenciesFulfilled = function runCaller() {
+ // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+ if (!calledRun) run();
+ if (!calledRun) dependenciesFulfilled = runCaller;
+};
+
+// try this again later, after new deps are fulfilled
+function run() {
+ if (runDependencies > 0) {
+ return;
+ }
+ preRun();
+ // a preRun added a dependency, run will be called later
+ if (runDependencies > 0) {
+ return;
+ }
+ function doRun() {
+ // run may have just been called through dependencies being fulfilled just in this very frame,
+ // or while the async setStatus time below was happening
+ if (calledRun) return;
+ calledRun = true;
+ Module["calledRun"] = true;
+ if (ABORT) return;
+ initRuntime();
+ readyPromiseResolve(Module);
+ Module["onRuntimeInitialized"]?.();
+ postRun();
+ }
+ if (Module["setStatus"]) {
+ Module["setStatus"]("Running...");
+ setTimeout(() => {
+ setTimeout(() => Module["setStatus"](""), 1);
+ doRun();
+ }, 1);
+ } else {
+ doRun();
+ }
+}
+
+if (Module["preInit"]) {
+ if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ];
+ while (Module["preInit"].length > 0) {
+ Module["preInit"].pop()();
+ }
+}
+
+run();
+
+// end include: postamble.js
+// include: postamble_modularize.js
+// In MODULARIZE mode we wrap the generated code in a factory function
+// and return either the Module itself, or a promise of the module.
+// We assign to the `moduleRtn` global here and configure closure to see
+// this as and extern so it won't get minified.
+moduleRtn = readyPromise;
+
+
+ return moduleRtn;
+}
+);
+})();
+if (typeof exports === 'object' && typeof module === 'object')
+ module.exports = setupModule;
+else if (typeof define === 'function' && define['amd'])
+ define([], () => setupModule);
diff --git a/wasm/TSF/build/tsf.js.symbols b/wasm/TSF/build/tsf.js.symbols
new file mode 100644
index 0000000..e161e3c
--- /dev/null
+++ b/wasm/TSF/build/tsf.js.symbols
@@ -0,0 +1,259 @@
+0:exit
+1:__syscall_fcntl64
+2:__syscall_ioctl
+3:__wasi_fd_close
+4:__wasi_fd_read
+5:__wasi_fd_write
+6:_abort_js
+7:_emscripten_memcpy_js
+8:emscripten_date_now
+9:__syscall_openat
+10:__wasi_environ_sizes_get
+11:__wasi_environ_get
+12:__syscall_unlinkat
+13:emscripten_resize_heap
+14:legalimport$__wasi_fd_seek
+15:__wasm_call_ctors
+16:tsf_vasprintf
+17:tsf_asprintf
+18:tsf_buffer_initialize_custom
+19:tsf_buffer_destroy_custom
+20:read_buffer_impl
+21:write_buffer_impl
+22:tsf_set_error_fullv
+23:tsf_set_error_full
+24:tsf_set_error
+25:tsf_set_errno
+26:new_size
+27:tsf_st_init_ptrtable
+28:tsf_st_init_strtable
+29:tsf_st_free_table
+30:tsf_st_lookup
+31:tsf_st_insert
+32:tsf_st_add_direct
+33:tsf_st_delete
+34:tsf_st_foreach
+35:tsf_st_strhash
+36:ptrcmp
+37:tsf_st_ptrhash
+38:tsf_type_create
+39:check_init_types
+40:tsf_type_recompute_hash
+41:tsf_type_destroy
+42:tsf_struct_type_append
+43:tsf_type_clone
+44:tsf_choice_type_append
+45:tsf_type_read_rec
+46:tsf_choice_type_get_num_elements
+47:tsf_type_write
+48:tsf_type_dup
+49:tsf_type_own_begin
+50:tsf_type_own_commit
+51:tsf_type_get_byte_size
+52:tsf_type_get_hash
+53:tsf_type_compare
+54:tsf_type_memo
+55:tsf_type_instanceof
+56:tsf_struct_type_get_num_elements
+57:tsf_struct_type_get_element
+58:tsf_struct_type_find_node
+59:tsf_choice_type_get_element
+60:tsf_choice_type_find_node
+61:tsf_type_get_static_size
+62:tsf_choice_type_has_non_void
+63:tsf_fd_writer
+64:tsf_fd_partial_reader
+65:tsf_size_calc_writer
+66:tsf_size_aware_reader
+67:tsf_native_type_has_struct_mapping
+68:tsf_native_type_get_size
+69:tsf_native_struct_type_map
+70:tsf_native_struct_type_set_size
+71:tsf_type_compare_adaptor
+72:tsf_parser_create
+73:tsf_parser_parse_into
+74:tsf_buf_writer_destroy
+75:tsf_buf_writer_write
+76:tsf_buf_reader_read
+77:tsf_type_table_create
+78:tsf_type_table_copy
+79:tsf_type_table_append
+80:tsf_type_table_find_by_index
+81:tsf_type_table_destroy
+82:tsf_type_table_read
+83:tsf_type_table_write
+84:tsf_type_table_get_hash
+85:tsf_type_table_contains_dynamic
+86:tsf_type_table_compare
+87:tsf_type_table_find_by_name
+88:generate_size_calc
+89:generate_generator
+90:generate_parser
+91:generate_set_default
+92:gpc_code_gen_debug
+93:gpc_threaded_destroy
+94:gpc_threaded_run
+95:back_branch_action
+96:fore_branch_action
+97:st_aa_free
+98:correct_branch
+99:gpc_intable_destroy
+100:gpc_intable_run
+101:gpc_instruction_static_size
+102:gpc_instruction_size
+103:gpc_instruction_for_all_branches
+104:gpc_program_from_proto
+105:gpc_program_run
+106:gpc_proto_create
+107:gpc_proto_destroy
+108:gpc_proto_append
+109:gpc_proto_append_tablejump_local
+110:gpc_proto_append_tablejump_field
+111:gpc_intable_get_stack_heights
+112:branch_action
+113:tsf_type_in_map_create
+114:tsf_type_in_map_from_type_out_map_in
+115:table_snatch_pair
+116:tsf_type_in_map_get_empty_singleton
+117:tsf_type_in_map_destroy
+118:tsf_type_in_map_prepare
+119:tsf_type_in_map_append
+120:tsf_type_in_map_get_type
+121:tsf_type_out_map_create
+122:tsf_type_out_map_destroy
+123:table_destroy_pair
+124:tsf_type_out_map_get_type_code
+125:tsf_stream_file_input_open
+126:tsf_stream_file_input_close
+127:tsf_stream_file_input_read_existing_buffer
+128:tsf_named_type_destroy
+129:tsf_named_type_get_hash
+130:tsf_read_string
+131:tsf_write_string
+132:tsf_full_read_of_partial
+133:tsf_zip_wtr_attr_get_default
+134:tsf_zip_rdr_attr_get_default
+135:tsf_zip_writer_destroy
+136:tsf_zip_writer_write
+137:tsf_zip_abstract_deflate
+138:tsf_adaptive_reader_destroy
+139:tear_down_mode
+140:tsf_adaptive_reader_read
+141:select_mode
+142:tsf_type_create_aoe
+143:aoe_failure
+144:tsf_type_create_array_aoe
+145:tsf_type_create_struct_with_native_size_aoe
+146:tsf_type_create_struct_with_native_size_and_destructor_aoe
+147:tsf_type_create_choice_with_native_map_aoe
+148:tsf_struct_type_append_primitive_with_native_map_aoe
+149:tsf_struct_type_append_from_callback_and_dup_with_native_map_aoe
+150:tsf_choice_type_append_primitive_aoe
+151:tsf_choice_type_append_from_callback_and_dup_aoe
+152:tsf_type_set_name_aoe
+153:tsf_typed_data_read
+154:Operand__get_type
+155:Type__get_type
+156:CodeOffset__get_type
+157:VariableDecl__destruct
+158:Instruction__alloc__destruct
+159:Instruction__call__destruct
+160:ProcedureDecl__get_type
+161:ProcedureDefn__get_type
+162:ProcedureDefn__destruct
+163:Program__get_type
+164:Program__get_parser
+165:Program__destruct
+166:Program__read
+167:Program__read_into
+168:Instruction__mov__get_type
+169:Instruction__add__get_type
+170:Instruction__alloc__get_type
+171:Instruction__ret__get_type
+172:Instruction__jump__get_type
+173:Instruction__call__get_type
+174:Instruction__call__args__get_type
+175:Instruction__branchZero__get_type
+176:ProcedureDefn__variables__get_type
+177:ProcedureDefn__code__get_type
+178:ProcedureDefn__debug__get_type
+179:Program__globals__get_type
+180:DOperand__get_type
+181:DType__get_type
+182:DCodeOffset__get_type
+183:DInstruction__call__destruct
+184:DProcedureDecl__get_type
+185:DProcedureDefn__get_type
+186:DProcedureDefn__destruct
+187:DProgram__destruct
+188:DProgram__read
+189:DInstruction__mov__get_type
+190:DInstruction__add__get_type
+191:DInstruction__alloc__get_type
+192:DInstruction__ret__get_type
+193:DInstruction__jump__get_type
+194:DInstruction__call__get_type
+195:DInstruction__call__args__get_type
+196:DInstruction__branchZero__get_type
+197:DProcedureDefn__variables__get_type
+198:DProcedureDefn__code__get_type
+199:DProgram__globals__get_type
+200:runIteration
+201:__stdio_close
+202:__stdio_read
+203:__stdio_seek
+204:__stdio_write
+205:abort
+206:close
+207:__memcpy
+208:__memset
+209:__gettimeofday
+210:fflush
+211:fiprintf
+212:__towrite
+213:__overflow
+214:fputc
+215:__fwritex
+216:getenv
+217:__bswap_32
+218:__lseek
+219:open
+220:__small_printf
+221:read
+222:snprintf
+223:__emscripten_stdout_close
+224:__emscripten_stdout_seek
+225:__stpcpy
+226:strchr
+227:__strchrnul
+228:strcmp
+229:strdup
+230:__strerror_l
+231:strlen
+232:__syscall_ret
+233:tolower
+234:vasprintf
+235:frexp
+236:__vfprintf_internal
+237:printf_core
+238:out
+239:getint
+240:pop_arg
+241:fmt_u
+242:pad
+243:fmt_fp
+244:pop_arg_long_double
+245:vsnprintf
+246:sn_write
+247:__wasi_syscall_ret
+248:wctomb
+249:emscripten_builtin_malloc
+250:emscripten_builtin_free
+251:dlrealloc
+252:dispose_chunk
+253:emscripten_builtin_calloc
+254:sbrk
+255:_emscripten_stack_restore
+256:_emscripten_stack_alloc
+257:emscripten_stack_get_current
+258:legalstub$dynCall_jiji
diff --git a/wasm/TSF/build/tsf.wasm b/wasm/TSF/build/tsf.wasm
new file mode 100755
index 0000000..c56dbcc
--- /dev/null
+++ b/wasm/TSF/build/tsf.wasm
Binary files differ
diff --git a/wasm/TSF/tsf_ir_speed.c b/wasm/TSF/tsf_ir_speed.c
index dd75c43..05eb656 100644
--- a/wasm/TSF/tsf_ir_speed.c
+++ b/wasm/TSF/tsf_ir_speed.c
@@ -321,47 +321,19 @@
tsf_stream_file_input_close(in);
}
-int main(int c, char **v) {
+int runIteration(unsigned count) {
static const char *filename = "tsf_ir_speed_test_file.tsf";
static const char *zipFilename = "tsf_ir_speed_test_zip_file.tsf";
-
- unsigned count;
-
- switch (c) {
- case 1:
- /* Use a small problem size suitable for regression testing. */
- count = 1000;
- break;
-
- case 2:
- if (sscanf(v[1], "%u", &count) != 1) {
- usage();
- }
- break;
-
- default:
- usage();
- return 1;
- }
-
- printf("Writing %u programs.\n", count);
- if (count != 10000)
- printf("WARNING: If you are benchmarking, please use count = 10000.\n");
-
+
TIMEIT(writeTest(filename, 100, count, TSF_ZIP_NONE));
TIMEIT(readTest(filename, count));
TIMEIT(readMallocTest(filename, count));
TIMEIT(readConvertTest(filename, count));
-
- if (tsf_zlib_supported()) {
- TIMEIT(writeTest(zipFilename, 100, count, TSF_ZIP_ZLIB));
- TIMEIT(readTest(zipFilename, count));
- TIMEIT(readMallocTest(filename, count));
- TIMEIT(readConvertTest(zipFilename, count));
- }
-
+
+ /* We don't benchmark zlib because it's not supported in JetStream */
+
/* We don't benchmark bzip2 because it's just too slow to be interesting. */
-
+
return 0;
}
diff --git a/wasm/gcc-loops.js b/wasm/gcc-loops.js
deleted file mode 100644
index 7ae8466..0000000
--- a/wasm/gcc-loops.js
+++ /dev/null
@@ -1,5437 +0,0 @@
-function doRun() {
-let __startupStartTime = benchmarkTime();
-var moduleOverrides = {};
-var key;
-for (key in Module) {
- if (Module.hasOwnProperty(key)) {
- moduleOverrides[key] = Module[key];
- }
-}
-Module["arguments"] = [];
-Module["thisProgram"] = "./this.program";
-Module["quit"] = (function(status, toThrow) {
- throw toThrow;
-});
-Module["preRun"] = [];
-Module["postRun"] = [];
-var ENVIRONMENT_IS_WEB = false;
-var ENVIRONMENT_IS_WORKER = false;
-var ENVIRONMENT_IS_NODE = false;
-var ENVIRONMENT_IS_SHELL = false;
-if (Module["ENVIRONMENT"]) {
- if (Module["ENVIRONMENT"] === "WEB") {
- ENVIRONMENT_IS_WEB = true;
- } else if (Module["ENVIRONMENT"] === "WORKER") {
- ENVIRONMENT_IS_WORKER = true;
- } else if (Module["ENVIRONMENT"] === "NODE") {
- ENVIRONMENT_IS_NODE = true;
- } else if (Module["ENVIRONMENT"] === "SHELL") {
- ENVIRONMENT_IS_SHELL = true;
- } else {
- throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.");
- }
-} else {
- ENVIRONMENT_IS_WEB = typeof window === "object";
- ENVIRONMENT_IS_WORKER = typeof importScripts === "function";
- ENVIRONMENT_IS_NODE = typeof process === "object" && typeof require === "function" && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER;
- ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
-}
-if (ENVIRONMENT_IS_NODE) {
- var nodeFS;
- var nodePath;
- Module["read"] = function shell_read(filename, binary) {
- var ret;
- if (!nodeFS) nodeFS = require("fs");
- if (!nodePath) nodePath = require("path");
- filename = nodePath["normalize"](filename);
- ret = nodeFS["readFileSync"](filename);
- return binary ? ret : ret.toString();
- };
- Module["readBinary"] = function readBinary(filename) {
- var ret = Module["read"](filename, true);
- if (!ret.buffer) {
- ret = new Uint8Array(ret);
- }
- assert(ret.buffer);
- return ret;
- };
- if (process["argv"].length > 1) {
- Module["thisProgram"] = process["argv"][1].replace(/\\/g, "/");
- }
- Module["arguments"] = process["argv"].slice(2);
- if (typeof module !== "undefined") {
- module["exports"] = Module;
- }
- process["on"]("uncaughtException", (function(ex) {
- if (!(ex instanceof ExitStatus)) {
- throw ex;
- }
- }));
- process["on"]("unhandledRejection", (function(reason, p) {
- process["exit"](1);
- }));
- Module["inspect"] = (function() {
- return "[Emscripten Module object]";
- });
-} else if (ENVIRONMENT_IS_SHELL) {
- if (typeof read != "undefined") {
- Module["read"] = function shell_read(f) {
- return read(f);
- };
- }
- Module["readBinary"] = function readBinary(f) {
- var data;
- if (typeof readbuffer === "function") {
- return new Uint8Array(readbuffer(f));
- }
- data = read(f, "binary");
- assert(typeof data === "object");
- return data;
- };
- if (typeof scriptArgs != "undefined") {
- Module["arguments"] = scriptArgs;
- } else if (typeof arguments != "undefined") {
- Module["arguments"] = arguments;
- }
- if (typeof quit === "function") {
- Module["quit"] = (function(status, toThrow) {
- quit(status);
- });
- }
-} else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
- Module["read"] = function shell_read(url) {
- var xhr = new XMLHttpRequest;
- xhr.open("GET", url, false);
- xhr.send(null);
- return xhr.responseText;
- };
- if (ENVIRONMENT_IS_WORKER) {
- Module["readBinary"] = function readBinary(url) {
- var xhr = new XMLHttpRequest;
- xhr.open("GET", url, false);
- xhr.responseType = "arraybuffer";
- xhr.send(null);
- return new Uint8Array(xhr.response);
- };
- }
- Module["readAsync"] = function readAsync(url, onload, onerror) {
- var xhr = new XMLHttpRequest;
- xhr.open("GET", url, true);
- xhr.responseType = "arraybuffer";
- xhr.onload = function xhr_onload() {
- if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
- onload(xhr.response);
- return;
- }
- onerror();
- };
- xhr.onerror = onerror;
- xhr.send(null);
- };
- Module["setWindowTitle"] = (function(title) {
- document.title = title;
- });
-}
-Module["print"] = typeof console !== "undefined" ? console.log.bind(console) : typeof print !== "undefined" ? print : null;
-Module["printErr"] = typeof printErr !== "undefined" ? printErr : typeof console !== "undefined" && console.warn.bind(console) || Module["print"];
-Module.print = Module["print"];
-Module.printErr = Module["printErr"];
-for (key in moduleOverrides) {
- if (moduleOverrides.hasOwnProperty(key)) {
- Module[key] = moduleOverrides[key];
- }
-}
-moduleOverrides = undefined;
-var STACK_ALIGN = 16;
-function staticAlloc(size) {
- assert(!staticSealed);
- var ret = STATICTOP;
- STATICTOP = STATICTOP + size + 15 & -16;
- return ret;
-}
-function dynamicAlloc(size) {
- assert(DYNAMICTOP_PTR);
- var ret = HEAP32[DYNAMICTOP_PTR >> 2];
- var end = ret + size + 15 & -16;
- HEAP32[DYNAMICTOP_PTR >> 2] = end;
- if (end >= TOTAL_MEMORY) {
- var success = enlargeMemory();
- if (!success) {
- HEAP32[DYNAMICTOP_PTR >> 2] = ret;
- return 0;
- }
- }
- return ret;
-}
-function alignMemory(size, factor) {
- if (!factor) factor = STACK_ALIGN;
- var ret = size = Math.ceil(size / factor) * factor;
- return ret;
-}
-function getNativeTypeSize(type) {
- switch (type) {
- case "i1":
- case "i8":
- return 1;
- case "i16":
- return 2;
- case "i32":
- return 4;
- case "i64":
- return 8;
- case "float":
- return 4;
- case "double":
- return 8;
- default:
- {
- if (type[type.length - 1] === "*") {
- return 4;
- } else if (type[0] === "i") {
- var bits = parseInt(type.substr(1));
- assert(bits % 8 === 0);
- return bits / 8;
- } else {
- return 0;
- }
- }
- }
-}
-function warnOnce(text) {
- if (!warnOnce.shown) warnOnce.shown = {};
- if (!warnOnce.shown[text]) {
- warnOnce.shown[text] = 1;
- Module.printErr(text);
- }
-}
-var jsCallStartIndex = 1;
-var functionPointers = new Array(0);
-var funcWrappers = {};
-function dynCall(sig, ptr, args) {
- if (args && args.length) {
- return Module["dynCall_" + sig].apply(null, [ ptr ].concat(args));
- } else {
- return Module["dynCall_" + sig].call(null, ptr);
- }
-}
-var GLOBAL_BASE = 1024;
-var ABORT = 0;
-var EXITSTATUS = 0;
-function assert(condition, text) {
- if (!condition) {
- abort("Assertion failed: " + text);
- }
-}
-function getCFunc(ident) {
- var func = Module["_" + ident];
- assert(func, "Cannot call unknown function " + ident + ", make sure it is exported");
- return func;
-}
-var JSfuncs = {
- "stackSave": (function() {
- stackSave();
- }),
- "stackRestore": (function() {
- stackRestore();
- }),
- "arrayToC": (function(arr) {
- var ret = stackAlloc(arr.length);
- writeArrayToMemory(arr, ret);
- return ret;
- }),
- "stringToC": (function(str) {
- var ret = 0;
- if (str !== null && str !== undefined && str !== 0) {
- var len = (str.length << 2) + 1;
- ret = stackAlloc(len);
- stringToUTF8(str, ret, len);
- }
- return ret;
- })
-};
-var toC = {
- "string": JSfuncs["stringToC"],
- "array": JSfuncs["arrayToC"]
-};
-function ccall(ident, returnType, argTypes, args, opts) {
- var func = getCFunc(ident);
- var cArgs = [];
- var stack = 0;
- if (args) {
- for (var i = 0; i < args.length; i++) {
- var converter = toC[argTypes[i]];
- if (converter) {
- if (stack === 0) stack = stackSave();
- cArgs[i] = converter(args[i]);
- } else {
- cArgs[i] = args[i];
- }
- }
- }
- var ret = func.apply(null, cArgs);
- if (returnType === "string") ret = Pointer_stringify(ret); else if (returnType === "boolean") ret = Boolean(ret);
- if (stack !== 0) {
- stackRestore(stack);
- }
- return ret;
-}
-function setValue(ptr, value, type, noSafe) {
- type = type || "i8";
- if (type.charAt(type.length - 1) === "*") type = "i32";
- switch (type) {
- case "i1":
- HEAP8[ptr >> 0] = value;
- break;
- case "i8":
- HEAP8[ptr >> 0] = value;
- break;
- case "i16":
- HEAP16[ptr >> 1] = value;
- break;
- case "i32":
- HEAP32[ptr >> 2] = value;
- break;
- case "i64":
- tempI64 = [ value >>> 0, (tempDouble = value, +Math_abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math_min(+Math_floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math_ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0) ], HEAP32[ptr >> 2] = tempI64[0], HEAP32[ptr + 4 >> 2] = tempI64[1];
- break;
- case "float":
- HEAPF32[ptr >> 2] = value;
- break;
- case "double":
- HEAPF64[ptr >> 3] = value;
- break;
- default:
- abort("invalid type for setValue: " + type);
- }
-}
-var ALLOC_STATIC = 2;
-var ALLOC_NONE = 4;
-function Pointer_stringify(ptr, length) {
- if (length === 0 || !ptr) return "";
- var hasUtf = 0;
- var t;
- var i = 0;
- while (1) {
- t = HEAPU8[ptr + i >> 0];
- hasUtf |= t;
- if (t == 0 && !length) break;
- i++;
- if (length && i == length) break;
- }
- if (!length) length = i;
- var ret = "";
- if (hasUtf < 128) {
- var MAX_CHUNK = 1024;
- var curr;
- while (length > 0) {
- curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
- ret = ret ? ret + curr : curr;
- ptr += MAX_CHUNK;
- length -= MAX_CHUNK;
- }
- return ret;
- }
- return UTF8ToString(ptr);
-}
-var UTF8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf8") : undefined;
-function UTF8ArrayToString(u8Array, idx) {
- var endPtr = idx;
- while (u8Array[endPtr]) ++endPtr;
- if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) {
- return UTF8Decoder.decode(u8Array.subarray(idx, endPtr));
- } else {
- var u0, u1, u2, u3, u4, u5;
- var str = "";
- while (1) {
- u0 = u8Array[idx++];
- if (!u0) return str;
- if (!(u0 & 128)) {
- str += String.fromCharCode(u0);
- continue;
- }
- u1 = u8Array[idx++] & 63;
- if ((u0 & 224) == 192) {
- str += String.fromCharCode((u0 & 31) << 6 | u1);
- continue;
- }
- u2 = u8Array[idx++] & 63;
- if ((u0 & 240) == 224) {
- u0 = (u0 & 15) << 12 | u1 << 6 | u2;
- } else {
- u3 = u8Array[idx++] & 63;
- if ((u0 & 248) == 240) {
- u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | u3;
- } else {
- u4 = u8Array[idx++] & 63;
- if ((u0 & 252) == 248) {
- u0 = (u0 & 3) << 24 | u1 << 18 | u2 << 12 | u3 << 6 | u4;
- } else {
- u5 = u8Array[idx++] & 63;
- u0 = (u0 & 1) << 30 | u1 << 24 | u2 << 18 | u3 << 12 | u4 << 6 | u5;
- }
- }
- }
- if (u0 < 65536) {
- str += String.fromCharCode(u0);
- } else {
- var ch = u0 - 65536;
- str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023);
- }
- }
- }
-}
-function UTF8ToString(ptr) {
- return UTF8ArrayToString(HEAPU8, ptr);
-}
-function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) {
- if (!(maxBytesToWrite > 0)) return 0;
- var startIdx = outIdx;
- var endIdx = outIdx + maxBytesToWrite - 1;
- for (var i = 0; i < str.length; ++i) {
- var u = str.charCodeAt(i);
- if (u >= 55296 && u <= 57343) u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023;
- if (u <= 127) {
- if (outIdx >= endIdx) break;
- outU8Array[outIdx++] = u;
- } else if (u <= 2047) {
- if (outIdx + 1 >= endIdx) break;
- outU8Array[outIdx++] = 192 | u >> 6;
- outU8Array[outIdx++] = 128 | u & 63;
- } else if (u <= 65535) {
- if (outIdx + 2 >= endIdx) break;
- outU8Array[outIdx++] = 224 | u >> 12;
- outU8Array[outIdx++] = 128 | u >> 6 & 63;
- outU8Array[outIdx++] = 128 | u & 63;
- } else if (u <= 2097151) {
- if (outIdx + 3 >= endIdx) break;
- outU8Array[outIdx++] = 240 | u >> 18;
- outU8Array[outIdx++] = 128 | u >> 12 & 63;
- outU8Array[outIdx++] = 128 | u >> 6 & 63;
- outU8Array[outIdx++] = 128 | u & 63;
- } else if (u <= 67108863) {
- if (outIdx + 4 >= endIdx) break;
- outU8Array[outIdx++] = 248 | u >> 24;
- outU8Array[outIdx++] = 128 | u >> 18 & 63;
- outU8Array[outIdx++] = 128 | u >> 12 & 63;
- outU8Array[outIdx++] = 128 | u >> 6 & 63;
- outU8Array[outIdx++] = 128 | u & 63;
- } else {
- if (outIdx + 5 >= endIdx) break;
- outU8Array[outIdx++] = 252 | u >> 30;
- outU8Array[outIdx++] = 128 | u >> 24 & 63;
- outU8Array[outIdx++] = 128 | u >> 18 & 63;
- outU8Array[outIdx++] = 128 | u >> 12 & 63;
- outU8Array[outIdx++] = 128 | u >> 6 & 63;
- outU8Array[outIdx++] = 128 | u & 63;
- }
- }
- outU8Array[outIdx] = 0;
- return outIdx - startIdx;
-}
-function stringToUTF8(str, outPtr, maxBytesToWrite) {
- return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
-}
-function lengthBytesUTF8(str) {
- var len = 0;
- for (var i = 0; i < str.length; ++i) {
- var u = str.charCodeAt(i);
- if (u >= 55296 && u <= 57343) u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023;
- if (u <= 127) {
- ++len;
- } else if (u <= 2047) {
- len += 2;
- } else if (u <= 65535) {
- len += 3;
- } else if (u <= 2097151) {
- len += 4;
- } else if (u <= 67108863) {
- len += 5;
- } else {
- len += 6;
- }
- }
- return len;
-}
-var UTF16Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le") : undefined;
-function allocateUTF8(str) {
- var size = lengthBytesUTF8(str) + 1;
- var ret = _malloc(size);
- if (ret) stringToUTF8Array(str, HEAP8, ret, size);
- return ret;
-}
-function allocateUTF8OnStack(str) {
- var size = lengthBytesUTF8(str) + 1;
- var ret = stackAlloc(size);
- stringToUTF8Array(str, HEAP8, ret, size);
- return ret;
-}
-function demangle(func) {
- return func;
-}
-function demangleAll(text) {
- var regex = /__Z[\w\d_]+/g;
- return text.replace(regex, (function(x) {
- var y = demangle(x);
- return x === y ? x : x + " [" + y + "]";
- }));
-}
-function jsStackTrace() {
- var err = new Error;
- if (!err.stack) {
- try {
- throw new Error(0);
- } catch (e) {
- err = e;
- }
- if (!err.stack) {
- return "(no stack trace available)";
- }
- }
- return err.stack.toString();
-}
-function stackTrace() {
- var js = jsStackTrace();
- if (Module["extraStackTrace"]) js += "\n" + Module["extraStackTrace"]();
- return demangleAll(js);
-}
-var WASM_PAGE_SIZE = 65536;
-var ASMJS_PAGE_SIZE = 16777216;
-function alignUp(x, multiple) {
- if (x % multiple > 0) {
- x += multiple - x % multiple;
- }
- return x;
-}
-var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
-function updateGlobalBuffer(buf) {
- Module["buffer"] = buffer = buf;
-}
-function updateGlobalBufferViews() {
- Module["HEAP8"] = HEAP8 = new Int8Array(buffer);
- Module["HEAP16"] = HEAP16 = new Int16Array(buffer);
- Module["HEAP32"] = HEAP32 = new Int32Array(buffer);
- Module["HEAPU8"] = HEAPU8 = new Uint8Array(buffer);
- Module["HEAPU16"] = HEAPU16 = new Uint16Array(buffer);
- Module["HEAPU32"] = HEAPU32 = new Uint32Array(buffer);
- Module["HEAPF32"] = HEAPF32 = new Float32Array(buffer);
- Module["HEAPF64"] = HEAPF64 = new Float64Array(buffer);
-}
-var STATIC_BASE, STATICTOP, staticSealed;
-var STACK_BASE, STACKTOP, STACK_MAX;
-var DYNAMIC_BASE, DYNAMICTOP_PTR;
-STATIC_BASE = STATICTOP = STACK_BASE = STACKTOP = STACK_MAX = DYNAMIC_BASE = DYNAMICTOP_PTR = 0;
-staticSealed = false;
-function abortOnCannotGrowMemory() {
- abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value " + TOTAL_MEMORY + ", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ");
-}
-function enlargeMemory() {
- abortOnCannotGrowMemory();
-}
-var TOTAL_STACK = Module["TOTAL_STACK"] || 5242880;
-var TOTAL_MEMORY = Module["TOTAL_MEMORY"] || 67108864;
-if (TOTAL_MEMORY < TOTAL_STACK) Module.printErr("TOTAL_MEMORY should be larger than TOTAL_STACK, was " + TOTAL_MEMORY + "! (TOTAL_STACK=" + TOTAL_STACK + ")");
-if (Module["buffer"]) {
- buffer = Module["buffer"];
-} else {
- if (typeof WebAssembly === "object" && typeof WebAssembly.Memory === "function") {
- Module["wasmMemory"] = new WebAssembly.Memory({
- "initial": TOTAL_MEMORY / WASM_PAGE_SIZE,
- "maximum": TOTAL_MEMORY / WASM_PAGE_SIZE
- });
- buffer = Module["wasmMemory"].buffer;
- } else {
- buffer = new ArrayBuffer(TOTAL_MEMORY);
- }
- Module["buffer"] = buffer;
-}
-updateGlobalBufferViews();
-function getTotalMemory() {
- return TOTAL_MEMORY;
-}
-HEAP32[0] = 1668509029;
-HEAP16[1] = 25459;
-if (HEAPU8[2] !== 115 || HEAPU8[3] !== 99) throw "Runtime error: expected the system to be little-endian!";
-function callRuntimeCallbacks(callbacks) {
- while (callbacks.length > 0) {
- var callback = callbacks.shift();
- if (typeof callback == "function") {
- callback();
- continue;
- }
- var func = callback.func;
- if (typeof func === "number") {
- if (callback.arg === undefined) {
- Module["dynCall_v"](func);
- } else {
- Module["dynCall_vi"](func, callback.arg);
- }
- } else {
- func(callback.arg === undefined ? null : callback.arg);
- }
- }
-}
-var __ATPRERUN__ = [];
-var __ATINIT__ = [];
-var __ATMAIN__ = [];
-var __ATEXIT__ = [];
-var __ATPOSTRUN__ = [];
-var runtimeInitialized = false;
-var runtimeExited = false;
-function preRun() {
- if (Module["preRun"]) {
- if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ];
- while (Module["preRun"].length) {
- addOnPreRun(Module["preRun"].shift());
- }
- }
- callRuntimeCallbacks(__ATPRERUN__);
-}
-function ensureInitRuntime() {
- if (runtimeInitialized) return;
- runtimeInitialized = true;
- callRuntimeCallbacks(__ATINIT__);
-}
-function preMain() {
- callRuntimeCallbacks(__ATMAIN__);
-}
-function exitRuntime() {
- callRuntimeCallbacks(__ATEXIT__);
- runtimeExited = true;
-}
-function postRun() {
- if (Module["postRun"]) {
- if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ];
- while (Module["postRun"].length) {
- addOnPostRun(Module["postRun"].shift());
- }
- }
- callRuntimeCallbacks(__ATPOSTRUN__);
-}
-function addOnPreRun(cb) {
- __ATPRERUN__.unshift(cb);
-}
-function addOnPostRun(cb) {
- __ATPOSTRUN__.unshift(cb);
-}
-function writeArrayToMemory(array, buffer) {
- HEAP8.set(array, buffer);
-}
-function writeAsciiToMemory(str, buffer, dontAddNull) {
- for (var i = 0; i < str.length; ++i) {
- HEAP8[buffer++ >> 0] = str.charCodeAt(i);
- }
- if (!dontAddNull) HEAP8[buffer >> 0] = 0;
-}
-var Math_abs = Math.abs;
-var Math_cos = Math.cos;
-var Math_sin = Math.sin;
-var Math_tan = Math.tan;
-var Math_acos = Math.acos;
-var Math_asin = Math.asin;
-var Math_atan = Math.atan;
-var Math_atan2 = Math.atan2;
-var Math_exp = Math.exp;
-var Math_log = Math.log;
-var Math_sqrt = Math.sqrt;
-var Math_ceil = Math.ceil;
-var Math_floor = Math.floor;
-var Math_pow = Math.pow;
-var Math_imul = Math.imul;
-var Math_fround = Math.fround;
-var Math_round = Math.round;
-var Math_min = Math.min;
-var Math_max = Math.max;
-var Math_clz32 = Math.clz32;
-var Math_trunc = Math.trunc;
-var runDependencies = 0;
-var runDependencyWatcher = null;
-var dependenciesFulfilled = null;
-function getUniqueRunDependency(id) {
- return id;
-}
-function addRunDependency(id) {
- runDependencies++;
- if (Module["monitorRunDependencies"]) {
- Module["monitorRunDependencies"](runDependencies);
- }
-}
-function removeRunDependency(id) {
- runDependencies--;
- if (Module["monitorRunDependencies"]) {
- Module["monitorRunDependencies"](runDependencies);
- }
- if (runDependencies == 0) {
- if (runDependencyWatcher !== null) {
- clearInterval(runDependencyWatcher);
- runDependencyWatcher = null;
- }
- if (dependenciesFulfilled) {
- var callback = dependenciesFulfilled;
- dependenciesFulfilled = null;
- callback();
- }
- }
-}
-Module["preloadedImages"] = {};
-Module["preloadedAudios"] = {};
-var dataURIPrefix = "data:application/octet-stream;base64,";
-function isDataURI(filename) {
- return String.prototype.startsWith ? filename.startsWith(dataURIPrefix) : filename.indexOf(dataURIPrefix) === 0;
-}
-function integrateWasmJS() {
- var wasmTextFile = "gcc-loops.wast";
- var wasmBinaryFile = "gcc-loops.wasm";
- var asmjsCodeFile = "gcc-loops.temp.asm.js";
- if (typeof Module["locateFile"] === "function") {
- if (!isDataURI(wasmTextFile)) {
- wasmTextFile = Module["locateFile"](wasmTextFile);
- }
- if (!isDataURI(wasmBinaryFile)) {
- wasmBinaryFile = Module["locateFile"](wasmBinaryFile);
- }
- if (!isDataURI(asmjsCodeFile)) {
- asmjsCodeFile = Module["locateFile"](asmjsCodeFile);
- }
- }
- var wasmPageSize = 64 * 1024;
- var info = {
- "global": null,
- "env": null,
- "asm2wasm": {
- "f64-rem": (function(x, y) {
- return x % y;
- }),
- "debugger": (function() {
- debugger;
- })
- },
- "parent": Module
- };
- var exports = null;
- function mergeMemory(newBuffer) {
- var oldBuffer = Module["buffer"];
- if (newBuffer.byteLength < oldBuffer.byteLength) {
- Module["printErr"]("the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here");
- }
- var oldView = new Int8Array(oldBuffer);
- var newView = new Int8Array(newBuffer);
- newView.set(oldView);
- updateGlobalBuffer(newBuffer);
- updateGlobalBufferViews();
- }
- function fixImports(imports) {
- return imports;
- }
- function getBinary() {
- try {
- if (Module["wasmBinary"]) {
- return new Uint8Array(Module["wasmBinary"]);
- }
- throw "on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)";
- } catch (err) {
- abort(err);
- }
- }
- function getBinaryPromise() {
- if (!Module["wasmBinary"] && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === "function") {
- return fetch(wasmBinaryFile, {
- credentials: "same-origin"
- }).then((function(response) {
- if (!response["ok"]) {
- throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
- }
- return response["arrayBuffer"]();
- })).catch((function() {
- return getBinary();
- }));
- }
- return new Promise((function(resolve, reject) {
- resolve(getBinary());
- }));
- }
- function doNativeWasm(global, env, providedBuffer) {
- if (typeof WebAssembly !== "object") {
- Module["printErr"]("no native wasm support detected");
- return false;
- }
- if (!(Module["wasmMemory"] instanceof WebAssembly.Memory)) {
- Module["printErr"]("no native wasm Memory in use");
- return false;
- }
- env["memory"] = Module["wasmMemory"];
- info["global"] = {
- "NaN": NaN,
- "Infinity": Infinity
- };
- info["global.Math"] = Math;
- info["env"] = env;
- function receiveInstance(instance, module) {
- exports = instance.exports;
- if (exports.memory) mergeMemory(exports.memory);
- Module["asm"] = exports;
- Module["usingWasm"] = true;
- removeRunDependency("wasm-instantiate");
- }
- addRunDependency("wasm-instantiate");
- if (Module["instantiateWasm"]) {
- try {
- return Module["instantiateWasm"](info, receiveInstance);
- } catch (e) {
- Module["printErr"]("Module.instantiateWasm callback failed with error: " + e);
- return false;
- }
- }
- function receiveInstantiatedSource(output) {
- receiveInstance(output["instance"], output["module"]);
- }
- function instantiateArrayBuffer(receiver) {
- getBinaryPromise().then((function(binary) {
- return WebAssembly.instantiate(binary, info);
- }))
- .then((...args) => {
- reportCompileTime(benchmarkTime() - __startupStartTime);
- return Promise.resolve(...args);
- })
- .then(receiver).catch((function(reason) {
- Module["printErr"]("failed to asynchronously prepare wasm: " + reason);
- abort(reason);
- }));
- }
- if (!Module["wasmBinary"] && typeof WebAssembly.instantiateStreaming === "function" && !isDataURI(wasmBinaryFile) && typeof fetch === "function") {
- WebAssembly.instantiateStreaming(fetch(wasmBinaryFile, {
- credentials: "same-origin"
- }), info).then(receiveInstantiatedSource).catch((function(reason) {
- Module["printErr"]("wasm streaming compile failed: " + reason);
- Module["printErr"]("falling back to ArrayBuffer instantiation");
- instantiateArrayBuffer(receiveInstantiatedSource);
- }));
- } else {
- instantiateArrayBuffer(receiveInstantiatedSource);
- }
- return {};
- }
- Module["asmPreload"] = Module["asm"];
- var asmjsReallocBuffer = Module["reallocBuffer"];
- var wasmReallocBuffer = (function(size) {
- var PAGE_MULTIPLE = Module["usingWasm"] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE;
- size = alignUp(size, PAGE_MULTIPLE);
- var old = Module["buffer"];
- var oldSize = old.byteLength;
- if (Module["usingWasm"]) {
- try {
- var result = Module["wasmMemory"].grow((size - oldSize) / wasmPageSize);
- if (result !== (-1 | 0)) {
- return Module["buffer"] = Module["wasmMemory"].buffer;
- } else {
- return null;
- }
- } catch (e) {
- return null;
- }
- }
- });
- Module["reallocBuffer"] = (function(size) {
- if (finalMethod === "asmjs") {
- return asmjsReallocBuffer(size);
- } else {
- return wasmReallocBuffer(size);
- }
- });
- var finalMethod = "";
- Module["asm"] = (function(global, env, providedBuffer) {
- env = fixImports(env);
- if (!env["table"]) {
- var TABLE_SIZE = Module["wasmTableSize"];
- if (TABLE_SIZE === undefined) TABLE_SIZE = 1024;
- var MAX_TABLE_SIZE = Module["wasmMaxTableSize"];
- if (typeof WebAssembly === "object" && typeof WebAssembly.Table === "function") {
- if (MAX_TABLE_SIZE !== undefined) {
- env["table"] = new WebAssembly.Table({
- "initial": TABLE_SIZE,
- "maximum": MAX_TABLE_SIZE,
- "element": "anyfunc"
- });
- } else {
- env["table"] = new WebAssembly.Table({
- "initial": TABLE_SIZE,
- element: "anyfunc"
- });
- }
- } else {
- env["table"] = new Array(TABLE_SIZE);
- }
- Module["wasmTable"] = env["table"];
- }
- if (!env["memoryBase"]) {
- env["memoryBase"] = Module["STATIC_BASE"];
- }
- if (!env["tableBase"]) {
- env["tableBase"] = 0;
- }
- var exports;
- exports = doNativeWasm(global, env, providedBuffer);
- if (!exports) abort("no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods");
- return exports;
- });
-}
-integrateWasmJS();
-STATIC_BASE = GLOBAL_BASE;
-STATICTOP = STATIC_BASE + 242832;
-__ATINIT__.push({
- func: (function() {
- __GLOBAL__I_000101();
- })
-}, {
- func: (function() {
- __GLOBAL__sub_I_iostream_cpp();
- })
-});
-var STATIC_BUMP = 242832;
-Module["STATIC_BASE"] = STATIC_BASE;
-Module["STATIC_BUMP"] = STATIC_BUMP;
-var tempDoublePtr = STATICTOP;
-STATICTOP += 16;
-function __ZSt18uncaught_exceptionv() {
- return !!__ZSt18uncaught_exceptionv.uncaught_exception;
-}
-function ___cxa_allocate_exception(size) {
- return _malloc(size);
-}
-var EXCEPTIONS = {
- last: 0,
- caught: [],
- infos: {},
- deAdjust: (function(adjusted) {
- if (!adjusted || EXCEPTIONS.infos[adjusted]) return adjusted;
- for (var key in EXCEPTIONS.infos) {
- var ptr = +key;
- var info = EXCEPTIONS.infos[ptr];
- if (info.adjusted === adjusted) {
- return ptr;
- }
- }
- return adjusted;
- }),
- addRef: (function(ptr) {
- if (!ptr) return;
- var info = EXCEPTIONS.infos[ptr];
- info.refcount++;
- }),
- decRef: (function(ptr) {
- if (!ptr) return;
- var info = EXCEPTIONS.infos[ptr];
- assert(info.refcount > 0);
- info.refcount--;
- if (info.refcount === 0 && !info.rethrown) {
- if (info.destructor) {
- Module["dynCall_vi"](info.destructor, ptr);
- }
- delete EXCEPTIONS.infos[ptr];
- ___cxa_free_exception(ptr);
- }
- }),
- clearRef: (function(ptr) {
- if (!ptr) return;
- var info = EXCEPTIONS.infos[ptr];
- info.refcount = 0;
- })
-};
-function ___cxa_begin_catch(ptr) {
- var info = EXCEPTIONS.infos[ptr];
- if (info && !info.caught) {
- info.caught = true;
- __ZSt18uncaught_exceptionv.uncaught_exception--;
- }
- if (info) info.rethrown = false;
- EXCEPTIONS.caught.push(ptr);
- EXCEPTIONS.addRef(EXCEPTIONS.deAdjust(ptr));
- return ptr;
-}
-function ___resumeException(ptr) {
- if (!EXCEPTIONS.last) {
- EXCEPTIONS.last = ptr;
- }
- throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
-}
-function ___cxa_find_matching_catch() {
- var thrown = EXCEPTIONS.last;
- if (!thrown) {
- return (setTempRet0(0), 0) | 0;
- }
- var info = EXCEPTIONS.infos[thrown];
- var throwntype = info.type;
- if (!throwntype) {
- return (setTempRet0(0), thrown) | 0;
- }
- var typeArray = Array.prototype.slice.call(arguments);
- var pointer = Module["___cxa_is_pointer_type"](throwntype);
- if (!___cxa_find_matching_catch.buffer) ___cxa_find_matching_catch.buffer = _malloc(4);
- HEAP32[___cxa_find_matching_catch.buffer >> 2] = thrown;
- thrown = ___cxa_find_matching_catch.buffer;
- for (var i = 0; i < typeArray.length; i++) {
- if (typeArray[i] && Module["___cxa_can_catch"](typeArray[i], throwntype, thrown)) {
- thrown = HEAP32[thrown >> 2];
- info.adjusted = thrown;
- return (setTempRet0(typeArray[i]), thrown) | 0;
- }
- }
- thrown = HEAP32[thrown >> 2];
- return (setTempRet0(throwntype), thrown) | 0;
-}
-function ___cxa_throw(ptr, type, destructor) {
- EXCEPTIONS.infos[ptr] = {
- ptr: ptr,
- adjusted: ptr,
- type: type,
- destructor: destructor,
- refcount: 0,
- caught: false,
- rethrown: false
- };
- EXCEPTIONS.last = ptr;
- if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
- __ZSt18uncaught_exceptionv.uncaught_exception = 1;
- } else {
- __ZSt18uncaught_exceptionv.uncaught_exception++;
- }
- throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
-}
-function ___gxx_personality_v0() {}
-function ___lock() {}
-var ERRNO_CODES = {
- EPERM: 1,
- ENOENT: 2,
- ESRCH: 3,
- EINTR: 4,
- EIO: 5,
- ENXIO: 6,
- E2BIG: 7,
- ENOEXEC: 8,
- EBADF: 9,
- ECHILD: 10,
- EAGAIN: 11,
- EWOULDBLOCK: 11,
- ENOMEM: 12,
- EACCES: 13,
- EFAULT: 14,
- ENOTBLK: 15,
- EBUSY: 16,
- EEXIST: 17,
- EXDEV: 18,
- ENODEV: 19,
- ENOTDIR: 20,
- EISDIR: 21,
- EINVAL: 22,
- ENFILE: 23,
- EMFILE: 24,
- ENOTTY: 25,
- ETXTBSY: 26,
- EFBIG: 27,
- ENOSPC: 28,
- ESPIPE: 29,
- EROFS: 30,
- EMLINK: 31,
- EPIPE: 32,
- EDOM: 33,
- ERANGE: 34,
- ENOMSG: 42,
- EIDRM: 43,
- ECHRNG: 44,
- EL2NSYNC: 45,
- EL3HLT: 46,
- EL3RST: 47,
- ELNRNG: 48,
- EUNATCH: 49,
- ENOCSI: 50,
- EL2HLT: 51,
- EDEADLK: 35,
- ENOLCK: 37,
- EBADE: 52,
- EBADR: 53,
- EXFULL: 54,
- ENOANO: 55,
- EBADRQC: 56,
- EBADSLT: 57,
- EDEADLOCK: 35,
- EBFONT: 59,
- ENOSTR: 60,
- ENODATA: 61,
- ETIME: 62,
- ENOSR: 63,
- ENONET: 64,
- ENOPKG: 65,
- EREMOTE: 66,
- ENOLINK: 67,
- EADV: 68,
- ESRMNT: 69,
- ECOMM: 70,
- EPROTO: 71,
- EMULTIHOP: 72,
- EDOTDOT: 73,
- EBADMSG: 74,
- ENOTUNIQ: 76,
- EBADFD: 77,
- EREMCHG: 78,
- ELIBACC: 79,
- ELIBBAD: 80,
- ELIBSCN: 81,
- ELIBMAX: 82,
- ELIBEXEC: 83,
- ENOSYS: 38,
- ENOTEMPTY: 39,
- ENAMETOOLONG: 36,
- ELOOP: 40,
- EOPNOTSUPP: 95,
- EPFNOSUPPORT: 96,
- ECONNRESET: 104,
- ENOBUFS: 105,
- EAFNOSUPPORT: 97,
- EPROTOTYPE: 91,
- ENOTSOCK: 88,
- ENOPROTOOPT: 92,
- ESHUTDOWN: 108,
- ECONNREFUSED: 111,
- EADDRINUSE: 98,
- ECONNABORTED: 103,
- ENETUNREACH: 101,
- ENETDOWN: 100,
- ETIMEDOUT: 110,
- EHOSTDOWN: 112,
- EHOSTUNREACH: 113,
- EINPROGRESS: 115,
- EALREADY: 114,
- EDESTADDRREQ: 89,
- EMSGSIZE: 90,
- EPROTONOSUPPORT: 93,
- ESOCKTNOSUPPORT: 94,
- EADDRNOTAVAIL: 99,
- ENETRESET: 102,
- EISCONN: 106,
- ENOTCONN: 107,
- ETOOMANYREFS: 109,
- EUSERS: 87,
- EDQUOT: 122,
- ESTALE: 116,
- ENOTSUP: 95,
- ENOMEDIUM: 123,
- EILSEQ: 84,
- EOVERFLOW: 75,
- ECANCELED: 125,
- ENOTRECOVERABLE: 131,
- EOWNERDEAD: 130,
- ESTRPIPE: 86
-};
-function ___setErrNo(value) {
- if (Module["___errno_location"]) HEAP32[Module["___errno_location"]() >> 2] = value;
- return value;
-}
-function ___map_file(pathname, size) {
- ___setErrNo(ERRNO_CODES.EPERM);
- return -1;
-}
-var ERRNO_MESSAGES = {
- 0: "Success",
- 1: "Not super-user",
- 2: "No such file or directory",
- 3: "No such process",
- 4: "Interrupted system call",
- 5: "I/O error",
- 6: "No such device or address",
- 7: "Arg list too long",
- 8: "Exec format error",
- 9: "Bad file number",
- 10: "No children",
- 11: "No more processes",
- 12: "Not enough core",
- 13: "Permission denied",
- 14: "Bad address",
- 15: "Block device required",
- 16: "Mount device busy",
- 17: "File exists",
- 18: "Cross-device link",
- 19: "No such device",
- 20: "Not a directory",
- 21: "Is a directory",
- 22: "Invalid argument",
- 23: "Too many open files in system",
- 24: "Too many open files",
- 25: "Not a typewriter",
- 26: "Text file busy",
- 27: "File too large",
- 28: "No space left on device",
- 29: "Illegal seek",
- 30: "Read only file system",
- 31: "Too many links",
- 32: "Broken pipe",
- 33: "Math arg out of domain of func",
- 34: "Math result not representable",
- 35: "File locking deadlock error",
- 36: "File or path name too long",
- 37: "No record locks available",
- 38: "Function not implemented",
- 39: "Directory not empty",
- 40: "Too many symbolic links",
- 42: "No message of desired type",
- 43: "Identifier removed",
- 44: "Channel number out of range",
- 45: "Level 2 not synchronized",
- 46: "Level 3 halted",
- 47: "Level 3 reset",
- 48: "Link number out of range",
- 49: "Protocol driver not attached",
- 50: "No CSI structure available",
- 51: "Level 2 halted",
- 52: "Invalid exchange",
- 53: "Invalid request descriptor",
- 54: "Exchange full",
- 55: "No anode",
- 56: "Invalid request code",
- 57: "Invalid slot",
- 59: "Bad font file fmt",
- 60: "Device not a stream",
- 61: "No data (for no delay io)",
- 62: "Timer expired",
- 63: "Out of streams resources",
- 64: "Machine is not on the network",
- 65: "Package not installed",
- 66: "The object is remote",
- 67: "The link has been severed",
- 68: "Advertise error",
- 69: "Srmount error",
- 70: "Communication error on send",
- 71: "Protocol error",
- 72: "Multihop attempted",
- 73: "Cross mount point (not really error)",
- 74: "Trying to read unreadable message",
- 75: "Value too large for defined data type",
- 76: "Given log. name not unique",
- 77: "f.d. invalid for this operation",
- 78: "Remote address changed",
- 79: "Can access a needed shared lib",
- 80: "Accessing a corrupted shared lib",
- 81: ".lib section in a.out corrupted",
- 82: "Attempting to link in too many libs",
- 83: "Attempting to exec a shared library",
- 84: "Illegal byte sequence",
- 86: "Streams pipe error",
- 87: "Too many users",
- 88: "Socket operation on non-socket",
- 89: "Destination address required",
- 90: "Message too long",
- 91: "Protocol wrong type for socket",
- 92: "Protocol not available",
- 93: "Unknown protocol",
- 94: "Socket type not supported",
- 95: "Not supported",
- 96: "Protocol family not supported",
- 97: "Address family not supported by protocol family",
- 98: "Address already in use",
- 99: "Address not available",
- 100: "Network interface is not configured",
- 101: "Network is unreachable",
- 102: "Connection reset by network",
- 103: "Connection aborted",
- 104: "Connection reset by peer",
- 105: "No buffer space available",
- 106: "Socket is already connected",
- 107: "Socket is not connected",
- 108: "Can't send after socket shutdown",
- 109: "Too many references",
- 110: "Connection timed out",
- 111: "Connection refused",
- 112: "Host is down",
- 113: "Host is unreachable",
- 114: "Socket already connected",
- 115: "Connection already in progress",
- 116: "Stale file handle",
- 122: "Quota exceeded",
- 123: "No medium (in tape drive)",
- 125: "Operation canceled",
- 130: "Previous owner died",
- 131: "State not recoverable"
-};
-var PATH = {
- splitPath: (function(filename) {
- var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
- return splitPathRe.exec(filename).slice(1);
- }),
- normalizeArray: (function(parts, allowAboveRoot) {
- var up = 0;
- for (var i = parts.length - 1; i >= 0; i--) {
- var last = parts[i];
- if (last === ".") {
- parts.splice(i, 1);
- } else if (last === "..") {
- parts.splice(i, 1);
- up++;
- } else if (up) {
- parts.splice(i, 1);
- up--;
- }
- }
- if (allowAboveRoot) {
- for (; up; up--) {
- parts.unshift("..");
- }
- }
- return parts;
- }),
- normalize: (function(path) {
- var isAbsolute = path.charAt(0) === "/", trailingSlash = path.substr(-1) === "/";
- path = PATH.normalizeArray(path.split("/").filter((function(p) {
- return !!p;
- })), !isAbsolute).join("/");
- if (!path && !isAbsolute) {
- path = ".";
- }
- if (path && trailingSlash) {
- path += "/";
- }
- return (isAbsolute ? "/" : "") + path;
- }),
- dirname: (function(path) {
- var result = PATH.splitPath(path), root = result[0], dir = result[1];
- if (!root && !dir) {
- return ".";
- }
- if (dir) {
- dir = dir.substr(0, dir.length - 1);
- }
- return root + dir;
- }),
- basename: (function(path) {
- if (path === "/") return "/";
- var lastSlash = path.lastIndexOf("/");
- if (lastSlash === -1) return path;
- return path.substr(lastSlash + 1);
- }),
- extname: (function(path) {
- return PATH.splitPath(path)[3];
- }),
- join: (function() {
- var paths = Array.prototype.slice.call(arguments, 0);
- return PATH.normalize(paths.join("/"));
- }),
- join2: (function(l, r) {
- return PATH.normalize(l + "/" + r);
- }),
- resolve: (function() {
- var resolvedPath = "", resolvedAbsolute = false;
- for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
- var path = i >= 0 ? arguments[i] : FS.cwd();
- if (typeof path !== "string") {
- throw new TypeError("Arguments to path.resolve must be strings");
- } else if (!path) {
- return "";
- }
- resolvedPath = path + "/" + resolvedPath;
- resolvedAbsolute = path.charAt(0) === "/";
- }
- resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter((function(p) {
- return !!p;
- })), !resolvedAbsolute).join("/");
- return (resolvedAbsolute ? "/" : "") + resolvedPath || ".";
- }),
- relative: (function(from, to) {
- from = PATH.resolve(from).substr(1);
- to = PATH.resolve(to).substr(1);
- function trim(arr) {
- var start = 0;
- for (; start < arr.length; start++) {
- if (arr[start] !== "") break;
- }
- var end = arr.length - 1;
- for (; end >= 0; end--) {
- if (arr[end] !== "") break;
- }
- if (start > end) return [];
- return arr.slice(start, end - start + 1);
- }
- var fromParts = trim(from.split("/"));
- var toParts = trim(to.split("/"));
- var length = Math.min(fromParts.length, toParts.length);
- var samePartsLength = length;
- for (var i = 0; i < length; i++) {
- if (fromParts[i] !== toParts[i]) {
- samePartsLength = i;
- break;
- }
- }
- var outputParts = [];
- for (var i = samePartsLength; i < fromParts.length; i++) {
- outputParts.push("..");
- }
- outputParts = outputParts.concat(toParts.slice(samePartsLength));
- return outputParts.join("/");
- })
-};
-var TTY = {
- ttys: [],
- init: (function() {}),
- shutdown: (function() {}),
- register: (function(dev, ops) {
- TTY.ttys[dev] = {
- input: [],
- output: [],
- ops: ops
- };
- FS.registerDevice(dev, TTY.stream_ops);
- }),
- stream_ops: {
- open: (function(stream) {
- var tty = TTY.ttys[stream.node.rdev];
- if (!tty) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- stream.tty = tty;
- stream.seekable = false;
- }),
- close: (function(stream) {
- stream.tty.ops.flush(stream.tty);
- }),
- flush: (function(stream) {
- stream.tty.ops.flush(stream.tty);
- }),
- read: (function(stream, buffer, offset, length, pos) {
- if (!stream.tty || !stream.tty.ops.get_char) {
- throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
- }
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = stream.tty.ops.get_char(stream.tty);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset + i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- }),
- write: (function(stream, buffer, offset, length, pos) {
- if (!stream.tty || !stream.tty.ops.put_char) {
- throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
- }
- for (var i = 0; i < length; i++) {
- try {
- stream.tty.ops.put_char(stream.tty, buffer[offset + i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- })
- },
- default_tty_ops: {
- get_char: (function(tty) {
- if (!tty.input.length) {
- var result = null;
- if (ENVIRONMENT_IS_NODE) {
- var BUFSIZE = 256;
- var buf = new Buffer(BUFSIZE);
- var bytesRead = 0;
- var isPosixPlatform = process.platform != "win32";
- var fd = process.stdin.fd;
- if (isPosixPlatform) {
- var usingDevice = false;
- try {
- fd = fs.openSync("/dev/stdin", "r");
- usingDevice = true;
- } catch (e) {}
- }
- try {
- bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);
- } catch (e) {
- if (e.toString().indexOf("EOF") != -1) bytesRead = 0; else throw e;
- }
- if (usingDevice) {
- fs.closeSync(fd);
- }
- if (bytesRead > 0) {
- result = buf.slice(0, bytesRead).toString("utf-8");
- } else {
- result = null;
- }
- } else if (typeof window != "undefined" && typeof window.prompt == "function") {
- result = window.prompt("Input: ");
- if (result !== null) {
- result += "\n";
- }
- } else if (typeof readline == "function") {
- result = readline();
- if (result !== null) {
- result += "\n";
- }
- }
- if (!result) {
- return null;
- }
- tty.input = intArrayFromString(result, true);
- }
- return tty.input.shift();
- }),
- put_char: (function(tty, val) {
- if (val === null || val === 10) {
- Module["print"](UTF8ArrayToString(tty.output, 0));
- tty.output = [];
- } else {
- if (val != 0) tty.output.push(val);
- }
- }),
- flush: (function(tty) {
- if (tty.output && tty.output.length > 0) {
- Module["print"](UTF8ArrayToString(tty.output, 0));
- tty.output = [];
- }
- })
- },
- default_tty1_ops: {
- put_char: (function(tty, val) {
- if (val === null || val === 10) {
- Module["printErr"](UTF8ArrayToString(tty.output, 0));
- tty.output = [];
- } else {
- if (val != 0) tty.output.push(val);
- }
- }),
- flush: (function(tty) {
- if (tty.output && tty.output.length > 0) {
- Module["printErr"](UTF8ArrayToString(tty.output, 0));
- tty.output = [];
- }
- })
- }
-};
-var MEMFS = {
- ops_table: null,
- mount: (function(mount) {
- return MEMFS.createNode(null, "/", 16384 | 511, 0);
- }),
- createNode: (function(parent, name, mode, dev) {
- if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (!MEMFS.ops_table) {
- MEMFS.ops_table = {
- dir: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr,
- lookup: MEMFS.node_ops.lookup,
- mknod: MEMFS.node_ops.mknod,
- rename: MEMFS.node_ops.rename,
- unlink: MEMFS.node_ops.unlink,
- rmdir: MEMFS.node_ops.rmdir,
- readdir: MEMFS.node_ops.readdir,
- symlink: MEMFS.node_ops.symlink
- },
- stream: {
- llseek: MEMFS.stream_ops.llseek
- }
- },
- file: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr
- },
- stream: {
- llseek: MEMFS.stream_ops.llseek,
- read: MEMFS.stream_ops.read,
- write: MEMFS.stream_ops.write,
- allocate: MEMFS.stream_ops.allocate,
- mmap: MEMFS.stream_ops.mmap,
- msync: MEMFS.stream_ops.msync
- }
- },
- link: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr,
- readlink: MEMFS.node_ops.readlink
- },
- stream: {}
- },
- chrdev: {
- node: {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr
- },
- stream: FS.chrdev_stream_ops
- }
- };
- }
- var node = FS.createNode(parent, name, mode, dev);
- if (FS.isDir(node.mode)) {
- node.node_ops = MEMFS.ops_table.dir.node;
- node.stream_ops = MEMFS.ops_table.dir.stream;
- node.contents = {};
- } else if (FS.isFile(node.mode)) {
- node.node_ops = MEMFS.ops_table.file.node;
- node.stream_ops = MEMFS.ops_table.file.stream;
- node.usedBytes = 0;
- node.contents = null;
- } else if (FS.isLink(node.mode)) {
- node.node_ops = MEMFS.ops_table.link.node;
- node.stream_ops = MEMFS.ops_table.link.stream;
- } else if (FS.isChrdev(node.mode)) {
- node.node_ops = MEMFS.ops_table.chrdev.node;
- node.stream_ops = MEMFS.ops_table.chrdev.stream;
- }
- node.timestamp = Date.now();
- if (parent) {
- parent.contents[name] = node;
- }
- return node;
- }),
- getFileDataAsRegularArray: (function(node) {
- if (node.contents && node.contents.subarray) {
- var arr = [];
- for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]);
- return arr;
- }
- return node.contents;
- }),
- getFileDataAsTypedArray: (function(node) {
- if (!node.contents) return new Uint8Array;
- if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes);
- return new Uint8Array(node.contents);
- }),
- expandFileStorage: (function(node, newCapacity) {
- if (node.contents && node.contents.subarray && newCapacity > node.contents.length) {
- node.contents = MEMFS.getFileDataAsRegularArray(node);
- node.usedBytes = node.contents.length;
- }
- if (!node.contents || node.contents.subarray) {
- var prevCapacity = node.contents ? node.contents.length : 0;
- if (prevCapacity >= newCapacity) return;
- var CAPACITY_DOUBLING_MAX = 1024 * 1024;
- newCapacity = Math.max(newCapacity, prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125) | 0);
- if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);
- var oldContents = node.contents;
- node.contents = new Uint8Array(newCapacity);
- if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0);
- return;
- }
- if (!node.contents && newCapacity > 0) node.contents = [];
- while (node.contents.length < newCapacity) node.contents.push(0);
- }),
- resizeFileStorage: (function(node, newSize) {
- if (node.usedBytes == newSize) return;
- if (newSize == 0) {
- node.contents = null;
- node.usedBytes = 0;
- return;
- }
- if (!node.contents || node.contents.subarray) {
- var oldContents = node.contents;
- node.contents = new Uint8Array(new ArrayBuffer(newSize));
- if (oldContents) {
- node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes)));
- }
- node.usedBytes = newSize;
- return;
- }
- if (!node.contents) node.contents = [];
- if (node.contents.length > newSize) node.contents.length = newSize; else while (node.contents.length < newSize) node.contents.push(0);
- node.usedBytes = newSize;
- }),
- node_ops: {
- getattr: (function(node) {
- var attr = {};
- attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
- attr.ino = node.id;
- attr.mode = node.mode;
- attr.nlink = 1;
- attr.uid = 0;
- attr.gid = 0;
- attr.rdev = node.rdev;
- if (FS.isDir(node.mode)) {
- attr.size = 4096;
- } else if (FS.isFile(node.mode)) {
- attr.size = node.usedBytes;
- } else if (FS.isLink(node.mode)) {
- attr.size = node.link.length;
- } else {
- attr.size = 0;
- }
- attr.atime = new Date(node.timestamp);
- attr.mtime = new Date(node.timestamp);
- attr.ctime = new Date(node.timestamp);
- attr.blksize = 4096;
- attr.blocks = Math.ceil(attr.size / attr.blksize);
- return attr;
- }),
- setattr: (function(node, attr) {
- if (attr.mode !== undefined) {
- node.mode = attr.mode;
- }
- if (attr.timestamp !== undefined) {
- node.timestamp = attr.timestamp;
- }
- if (attr.size !== undefined) {
- MEMFS.resizeFileStorage(node, attr.size);
- }
- }),
- lookup: (function(parent, name) {
- throw FS.genericErrors[ERRNO_CODES.ENOENT];
- }),
- mknod: (function(parent, name, mode, dev) {
- return MEMFS.createNode(parent, name, mode, dev);
- }),
- rename: (function(old_node, new_dir, new_name) {
- if (FS.isDir(old_node.mode)) {
- var new_node;
- try {
- new_node = FS.lookupNode(new_dir, new_name);
- } catch (e) {}
- if (new_node) {
- for (var i in new_node.contents) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- }
- }
- delete old_node.parent.contents[old_node.name];
- old_node.name = new_name;
- new_dir.contents[new_name] = old_node;
- old_node.parent = new_dir;
- }),
- unlink: (function(parent, name) {
- delete parent.contents[name];
- }),
- rmdir: (function(parent, name) {
- var node = FS.lookupNode(parent, name);
- for (var i in node.contents) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- delete parent.contents[name];
- }),
- readdir: (function(node) {
- var entries = [ ".", ".." ];
- for (var key in node.contents) {
- if (!node.contents.hasOwnProperty(key)) {
- continue;
- }
- entries.push(key);
- }
- return entries;
- }),
- symlink: (function(parent, newname, oldpath) {
- var node = MEMFS.createNode(parent, newname, 511 | 40960, 0);
- node.link = oldpath;
- return node;
- }),
- readlink: (function(node) {
- if (!FS.isLink(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return node.link;
- })
- },
- stream_ops: {
- read: (function(stream, buffer, offset, length, position) {
- var contents = stream.node.contents;
- if (position >= stream.node.usedBytes) return 0;
- var size = Math.min(stream.node.usedBytes - position, length);
- assert(size >= 0);
- if (size > 8 && contents.subarray) {
- buffer.set(contents.subarray(position, position + size), offset);
- } else {
- for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
- }
- return size;
- }),
- write: (function(stream, buffer, offset, length, position, canOwn) {
- if (!length) return 0;
- var node = stream.node;
- node.timestamp = Date.now();
- if (buffer.subarray && (!node.contents || node.contents.subarray)) {
- if (canOwn) {
- node.contents = buffer.subarray(offset, offset + length);
- node.usedBytes = length;
- return length;
- } else if (node.usedBytes === 0 && position === 0) {
- node.contents = new Uint8Array(buffer.subarray(offset, offset + length));
- node.usedBytes = length;
- return length;
- } else if (position + length <= node.usedBytes) {
- node.contents.set(buffer.subarray(offset, offset + length), position);
- return length;
- }
- }
- MEMFS.expandFileStorage(node, position + length);
- if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position); else {
- for (var i = 0; i < length; i++) {
- node.contents[position + i] = buffer[offset + i];
- }
- }
- node.usedBytes = Math.max(node.usedBytes, position + length);
- return length;
- }),
- llseek: (function(stream, offset, whence) {
- var position = offset;
- if (whence === 1) {
- position += stream.position;
- } else if (whence === 2) {
- if (FS.isFile(stream.node.mode)) {
- position += stream.node.usedBytes;
- }
- }
- if (position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return position;
- }),
- allocate: (function(stream, offset, length) {
- MEMFS.expandFileStorage(stream.node, offset + length);
- stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);
- }),
- mmap: (function(stream, buffer, offset, length, position, prot, flags) {
- if (!FS.isFile(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- var ptr;
- var allocated;
- var contents = stream.node.contents;
- if (!(flags & 2) && (contents.buffer === buffer || contents.buffer === buffer.buffer)) {
- allocated = false;
- ptr = contents.byteOffset;
- } else {
- if (position > 0 || position + length < stream.node.usedBytes) {
- if (contents.subarray) {
- contents = contents.subarray(position, position + length);
- } else {
- contents = Array.prototype.slice.call(contents, position, position + length);
- }
- }
- allocated = true;
- ptr = _malloc(length);
- if (!ptr) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
- }
- buffer.set(contents, ptr);
- }
- return {
- ptr: ptr,
- allocated: allocated
- };
- }),
- msync: (function(stream, buffer, offset, length, mmapFlags) {
- if (!FS.isFile(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- if (mmapFlags & 2) {
- return 0;
- }
- var bytesWritten = MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
- return 0;
- })
- }
-};
-var IDBFS = {
- dbs: {},
- indexedDB: (function() {
- if (typeof indexedDB !== "undefined") return indexedDB;
- var ret = null;
- if (typeof window === "object") ret = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
- assert(ret, "IDBFS used, but indexedDB not supported");
- return ret;
- }),
- DB_VERSION: 21,
- DB_STORE_NAME: "FILE_DATA",
- mount: (function(mount) {
- return MEMFS.mount.apply(null, arguments);
- }),
- syncfs: (function(mount, populate, callback) {
- IDBFS.getLocalSet(mount, (function(err, local) {
- if (err) return callback(err);
- IDBFS.getRemoteSet(mount, (function(err, remote) {
- if (err) return callback(err);
- var src = populate ? remote : local;
- var dst = populate ? local : remote;
- IDBFS.reconcile(src, dst, callback);
- }));
- }));
- }),
- getDB: (function(name, callback) {
- var db = IDBFS.dbs[name];
- if (db) {
- return callback(null, db);
- }
- var req;
- try {
- req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
- } catch (e) {
- return callback(e);
- }
- if (!req) {
- return callback("Unable to connect to IndexedDB");
- }
- req.onupgradeneeded = (function(e) {
- var db = e.target.result;
- var transaction = e.target.transaction;
- var fileStore;
- if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
- fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
- } else {
- fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
- }
- if (!fileStore.indexNames.contains("timestamp")) {
- fileStore.createIndex("timestamp", "timestamp", {
- unique: false
- });
- }
- });
- req.onsuccess = (function() {
- db = req.result;
- IDBFS.dbs[name] = db;
- callback(null, db);
- });
- req.onerror = (function(e) {
- callback(this.error);
- e.preventDefault();
- });
- }),
- getLocalSet: (function(mount, callback) {
- var entries = {};
- function isRealDir(p) {
- return p !== "." && p !== "..";
- }
- function toAbsolute(root) {
- return (function(p) {
- return PATH.join2(root, p);
- });
- }
- var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
- while (check.length) {
- var path = check.pop();
- var stat;
- try {
- stat = FS.stat(path);
- } catch (e) {
- return callback(e);
- }
- if (FS.isDir(stat.mode)) {
- check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
- }
- entries[path] = {
- timestamp: stat.mtime
- };
- }
- return callback(null, {
- type: "local",
- entries: entries
- });
- }),
- getRemoteSet: (function(mount, callback) {
- var entries = {};
- IDBFS.getDB(mount.mountpoint, (function(err, db) {
- if (err) return callback(err);
- try {
- var transaction = db.transaction([ IDBFS.DB_STORE_NAME ], "readonly");
- transaction.onerror = (function(e) {
- callback(this.error);
- e.preventDefault();
- });
- var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
- var index = store.index("timestamp");
- index.openKeyCursor().onsuccess = (function(event) {
- var cursor = event.target.result;
- if (!cursor) {
- return callback(null, {
- type: "remote",
- db: db,
- entries: entries
- });
- }
- entries[cursor.primaryKey] = {
- timestamp: cursor.key
- };
- cursor.continue();
- });
- } catch (e) {
- return callback(e);
- }
- }));
- }),
- loadLocalEntry: (function(path, callback) {
- var stat, node;
- try {
- var lookup = FS.lookupPath(path);
- node = lookup.node;
- stat = FS.stat(path);
- } catch (e) {
- return callback(e);
- }
- if (FS.isDir(stat.mode)) {
- return callback(null, {
- timestamp: stat.mtime,
- mode: stat.mode
- });
- } else if (FS.isFile(stat.mode)) {
- node.contents = MEMFS.getFileDataAsTypedArray(node);
- return callback(null, {
- timestamp: stat.mtime,
- mode: stat.mode,
- contents: node.contents
- });
- } else {
- return callback(new Error("node type not supported"));
- }
- }),
- storeLocalEntry: (function(path, entry, callback) {
- try {
- if (FS.isDir(entry.mode)) {
- FS.mkdir(path, entry.mode);
- } else if (FS.isFile(entry.mode)) {
- FS.writeFile(path, entry.contents, {
- canOwn: true
- });
- } else {
- return callback(new Error("node type not supported"));
- }
- FS.chmod(path, entry.mode);
- FS.utime(path, entry.timestamp, entry.timestamp);
- } catch (e) {
- return callback(e);
- }
- callback(null);
- }),
- removeLocalEntry: (function(path, callback) {
- try {
- var lookup = FS.lookupPath(path);
- var stat = FS.stat(path);
- if (FS.isDir(stat.mode)) {
- FS.rmdir(path);
- } else if (FS.isFile(stat.mode)) {
- FS.unlink(path);
- }
- } catch (e) {
- return callback(e);
- }
- callback(null);
- }),
- loadRemoteEntry: (function(store, path, callback) {
- var req = store.get(path);
- req.onsuccess = (function(event) {
- callback(null, event.target.result);
- });
- req.onerror = (function(e) {
- callback(this.error);
- e.preventDefault();
- });
- }),
- storeRemoteEntry: (function(store, path, entry, callback) {
- var req = store.put(entry, path);
- req.onsuccess = (function() {
- callback(null);
- });
- req.onerror = (function(e) {
- callback(this.error);
- e.preventDefault();
- });
- }),
- removeRemoteEntry: (function(store, path, callback) {
- var req = store.delete(path);
- req.onsuccess = (function() {
- callback(null);
- });
- req.onerror = (function(e) {
- callback(this.error);
- e.preventDefault();
- });
- }),
- reconcile: (function(src, dst, callback) {
- var total = 0;
- var create = [];
- Object.keys(src.entries).forEach((function(key) {
- var e = src.entries[key];
- var e2 = dst.entries[key];
- if (!e2 || e.timestamp > e2.timestamp) {
- create.push(key);
- total++;
- }
- }));
- var remove = [];
- Object.keys(dst.entries).forEach((function(key) {
- var e = dst.entries[key];
- var e2 = src.entries[key];
- if (!e2) {
- remove.push(key);
- total++;
- }
- }));
- if (!total) {
- return callback(null);
- }
- var completed = 0;
- var db = src.type === "remote" ? src.db : dst.db;
- var transaction = db.transaction([ IDBFS.DB_STORE_NAME ], "readwrite");
- var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
- function done(err) {
- if (err) {
- if (!done.errored) {
- done.errored = true;
- return callback(err);
- }
- return;
- }
- if (++completed >= total) {
- return callback(null);
- }
- }
- transaction.onerror = (function(e) {
- done(this.error);
- e.preventDefault();
- });
- create.sort().forEach((function(path) {
- if (dst.type === "local") {
- IDBFS.loadRemoteEntry(store, path, (function(err, entry) {
- if (err) return done(err);
- IDBFS.storeLocalEntry(path, entry, done);
- }));
- } else {
- IDBFS.loadLocalEntry(path, (function(err, entry) {
- if (err) return done(err);
- IDBFS.storeRemoteEntry(store, path, entry, done);
- }));
- }
- }));
- remove.sort().reverse().forEach((function(path) {
- if (dst.type === "local") {
- IDBFS.removeLocalEntry(path, done);
- } else {
- IDBFS.removeRemoteEntry(store, path, done);
- }
- }));
- })
-};
-var NODEFS = {
- isWindows: false,
- staticInit: (function() {
- NODEFS.isWindows = !!process.platform.match(/^win/);
- var flags = process["binding"]("constants");
- if (flags["fs"]) {
- flags = flags["fs"];
- }
- NODEFS.flagsForNodeMap = {
- "1024": flags["O_APPEND"],
- "64": flags["O_CREAT"],
- "128": flags["O_EXCL"],
- "0": flags["O_RDONLY"],
- "2": flags["O_RDWR"],
- "4096": flags["O_SYNC"],
- "512": flags["O_TRUNC"],
- "1": flags["O_WRONLY"]
- };
- }),
- bufferFrom: (function(arrayBuffer) {
- return Buffer.alloc ? Buffer.from(arrayBuffer) : new Buffer(arrayBuffer);
- }),
- mount: (function(mount) {
- assert(ENVIRONMENT_IS_NODE);
- return NODEFS.createNode(null, "/", NODEFS.getMode(mount.opts.root), 0);
- }),
- createNode: (function(parent, name, mode, dev) {
- if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var node = FS.createNode(parent, name, mode);
- node.node_ops = NODEFS.node_ops;
- node.stream_ops = NODEFS.stream_ops;
- return node;
- }),
- getMode: (function(path) {
- var stat;
- try {
- stat = fs.lstatSync(path);
- if (NODEFS.isWindows) {
- stat.mode = stat.mode | (stat.mode & 292) >> 2;
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- return stat.mode;
- }),
- realPath: (function(node) {
- var parts = [];
- while (node.parent !== node) {
- parts.push(node.name);
- node = node.parent;
- }
- parts.push(node.mount.opts.root);
- parts.reverse();
- return PATH.join.apply(null, parts);
- }),
- flagsForNode: (function(flags) {
- flags &= ~2097152;
- flags &= ~2048;
- flags &= ~32768;
- flags &= ~524288;
- var newFlags = 0;
- for (var k in NODEFS.flagsForNodeMap) {
- if (flags & k) {
- newFlags |= NODEFS.flagsForNodeMap[k];
- flags ^= k;
- }
- }
- if (!flags) {
- return newFlags;
- } else {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- }),
- node_ops: {
- getattr: (function(node) {
- var path = NODEFS.realPath(node);
- var stat;
- try {
- stat = fs.lstatSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- if (NODEFS.isWindows && !stat.blksize) {
- stat.blksize = 4096;
- }
- if (NODEFS.isWindows && !stat.blocks) {
- stat.blocks = (stat.size + stat.blksize - 1) / stat.blksize | 0;
- }
- return {
- dev: stat.dev,
- ino: stat.ino,
- mode: stat.mode,
- nlink: stat.nlink,
- uid: stat.uid,
- gid: stat.gid,
- rdev: stat.rdev,
- size: stat.size,
- atime: stat.atime,
- mtime: stat.mtime,
- ctime: stat.ctime,
- blksize: stat.blksize,
- blocks: stat.blocks
- };
- }),
- setattr: (function(node, attr) {
- var path = NODEFS.realPath(node);
- try {
- if (attr.mode !== undefined) {
- fs.chmodSync(path, attr.mode);
- node.mode = attr.mode;
- }
- if (attr.timestamp !== undefined) {
- var date = new Date(attr.timestamp);
- fs.utimesSync(path, date, date);
- }
- if (attr.size !== undefined) {
- fs.truncateSync(path, attr.size);
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- lookup: (function(parent, name) {
- var path = PATH.join2(NODEFS.realPath(parent), name);
- var mode = NODEFS.getMode(path);
- return NODEFS.createNode(parent, name, mode);
- }),
- mknod: (function(parent, name, mode, dev) {
- var node = NODEFS.createNode(parent, name, mode, dev);
- var path = NODEFS.realPath(node);
- try {
- if (FS.isDir(node.mode)) {
- fs.mkdirSync(path, node.mode);
- } else {
- fs.writeFileSync(path, "", {
- mode: node.mode
- });
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- return node;
- }),
- rename: (function(oldNode, newDir, newName) {
- var oldPath = NODEFS.realPath(oldNode);
- var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
- try {
- fs.renameSync(oldPath, newPath);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- unlink: (function(parent, name) {
- var path = PATH.join2(NODEFS.realPath(parent), name);
- try {
- fs.unlinkSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- rmdir: (function(parent, name) {
- var path = PATH.join2(NODEFS.realPath(parent), name);
- try {
- fs.rmdirSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- readdir: (function(node) {
- var path = NODEFS.realPath(node);
- try {
- return fs.readdirSync(path);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- symlink: (function(parent, newName, oldPath) {
- var newPath = PATH.join2(NODEFS.realPath(parent), newName);
- try {
- fs.symlinkSync(oldPath, newPath);
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- readlink: (function(node) {
- var path = NODEFS.realPath(node);
- try {
- path = fs.readlinkSync(path);
- path = NODEJS_PATH.relative(NODEJS_PATH.resolve(node.mount.opts.root), path);
- return path;
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- })
- },
- stream_ops: {
- open: (function(stream) {
- var path = NODEFS.realPath(stream.node);
- try {
- if (FS.isFile(stream.node.mode)) {
- stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- close: (function(stream) {
- try {
- if (FS.isFile(stream.node.mode) && stream.nfd) {
- fs.closeSync(stream.nfd);
- }
- } catch (e) {
- if (!e.code) throw e;
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- read: (function(stream, buffer, offset, length, position) {
- if (length === 0) return 0;
- try {
- return fs.readSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- write: (function(stream, buffer, offset, length, position) {
- try {
- return fs.writeSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }),
- llseek: (function(stream, offset, whence) {
- var position = offset;
- if (whence === 1) {
- position += stream.position;
- } else if (whence === 2) {
- if (FS.isFile(stream.node.mode)) {
- try {
- var stat = fs.fstatSync(stream.nfd);
- position += stat.size;
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES[e.code]);
- }
- }
- }
- if (position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return position;
- })
- }
-};
-var WORKERFS = {
- DIR_MODE: 16895,
- FILE_MODE: 33279,
- reader: null,
- mount: (function(mount) {
- assert(ENVIRONMENT_IS_WORKER);
- if (!WORKERFS.reader) WORKERFS.reader = new FileReaderSync;
- var root = WORKERFS.createNode(null, "/", WORKERFS.DIR_MODE, 0);
- var createdParents = {};
- function ensureParent(path) {
- var parts = path.split("/");
- var parent = root;
- for (var i = 0; i < parts.length - 1; i++) {
- var curr = parts.slice(0, i + 1).join("/");
- if (!createdParents[curr]) {
- createdParents[curr] = WORKERFS.createNode(parent, parts[i], WORKERFS.DIR_MODE, 0);
- }
- parent = createdParents[curr];
- }
- return parent;
- }
- function base(path) {
- var parts = path.split("/");
- return parts[parts.length - 1];
- }
- Array.prototype.forEach.call(mount.opts["files"] || [], (function(file) {
- WORKERFS.createNode(ensureParent(file.name), base(file.name), WORKERFS.FILE_MODE, 0, file, file.lastModifiedDate);
- }));
- (mount.opts["blobs"] || []).forEach((function(obj) {
- WORKERFS.createNode(ensureParent(obj["name"]), base(obj["name"]), WORKERFS.FILE_MODE, 0, obj["data"]);
- }));
- (mount.opts["packages"] || []).forEach((function(pack) {
- pack["metadata"].files.forEach((function(file) {
- var name = file.filename.substr(1);
- WORKERFS.createNode(ensureParent(name), base(name), WORKERFS.FILE_MODE, 0, pack["blob"].slice(file.start, file.end));
- }));
- }));
- return root;
- }),
- createNode: (function(parent, name, mode, dev, contents, mtime) {
- var node = FS.createNode(parent, name, mode);
- node.mode = mode;
- node.node_ops = WORKERFS.node_ops;
- node.stream_ops = WORKERFS.stream_ops;
- node.timestamp = (mtime || new Date).getTime();
- assert(WORKERFS.FILE_MODE !== WORKERFS.DIR_MODE);
- if (mode === WORKERFS.FILE_MODE) {
- node.size = contents.size;
- node.contents = contents;
- } else {
- node.size = 4096;
- node.contents = {};
- }
- if (parent) {
- parent.contents[name] = node;
- }
- return node;
- }),
- node_ops: {
- getattr: (function(node) {
- return {
- dev: 1,
- ino: undefined,
- mode: node.mode,
- nlink: 1,
- uid: 0,
- gid: 0,
- rdev: undefined,
- size: node.size,
- atime: new Date(node.timestamp),
- mtime: new Date(node.timestamp),
- ctime: new Date(node.timestamp),
- blksize: 4096,
- blocks: Math.ceil(node.size / 4096)
- };
- }),
- setattr: (function(node, attr) {
- if (attr.mode !== undefined) {
- node.mode = attr.mode;
- }
- if (attr.timestamp !== undefined) {
- node.timestamp = attr.timestamp;
- }
- }),
- lookup: (function(parent, name) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }),
- mknod: (function(parent, name, mode, dev) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }),
- rename: (function(oldNode, newDir, newName) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }),
- unlink: (function(parent, name) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }),
- rmdir: (function(parent, name) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }),
- readdir: (function(node) {
- var entries = [ ".", ".." ];
- for (var key in node.contents) {
- if (!node.contents.hasOwnProperty(key)) {
- continue;
- }
- entries.push(key);
- }
- return entries;
- }),
- symlink: (function(parent, newName, oldPath) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }),
- readlink: (function(node) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- })
- },
- stream_ops: {
- read: (function(stream, buffer, offset, length, position) {
- if (position >= stream.node.size) return 0;
- var chunk = stream.node.contents.slice(position, position + length);
- var ab = WORKERFS.reader.readAsArrayBuffer(chunk);
- buffer.set(new Uint8Array(ab), offset);
- return chunk.size;
- }),
- write: (function(stream, buffer, offset, length, position) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }),
- llseek: (function(stream, offset, whence) {
- var position = offset;
- if (whence === 1) {
- position += stream.position;
- } else if (whence === 2) {
- if (FS.isFile(stream.node.mode)) {
- position += stream.node.size;
- }
- }
- if (position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return position;
- })
- }
-};
-STATICTOP += 16;
-STATICTOP += 16;
-STATICTOP += 16;
-var FS = {
- root: null,
- mounts: [],
- devices: {},
- streams: [],
- nextInode: 1,
- nameTable: null,
- currentPath: "/",
- initialized: false,
- ignorePermissions: true,
- trackingDelegate: {},
- tracking: {
- openFlags: {
- READ: 1,
- WRITE: 2
- }
- },
- ErrnoError: null,
- genericErrors: {},
- filesystems: null,
- syncFSRequests: 0,
- handleFSError: (function(e) {
- if (!(e instanceof FS.ErrnoError)) throw e + " : " + stackTrace();
- return ___setErrNo(e.errno);
- }),
- lookupPath: (function(path, opts) {
- path = PATH.resolve(FS.cwd(), path);
- opts = opts || {};
- if (!path) return {
- path: "",
- node: null
- };
- var defaults = {
- follow_mount: true,
- recurse_count: 0
- };
- for (var key in defaults) {
- if (opts[key] === undefined) {
- opts[key] = defaults[key];
- }
- }
- if (opts.recurse_count > 8) {
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
- var parts = PATH.normalizeArray(path.split("/").filter((function(p) {
- return !!p;
- })), false);
- var current = FS.root;
- var current_path = "/";
- for (var i = 0; i < parts.length; i++) {
- var islast = i === parts.length - 1;
- if (islast && opts.parent) {
- break;
- }
- current = FS.lookupNode(current, parts[i]);
- current_path = PATH.join2(current_path, parts[i]);
- if (FS.isMountpoint(current)) {
- if (!islast || islast && opts.follow_mount) {
- current = current.mounted.root;
- }
- }
- if (!islast || opts.follow) {
- var count = 0;
- while (FS.isLink(current.mode)) {
- var link = FS.readlink(current_path);
- current_path = PATH.resolve(PATH.dirname(current_path), link);
- var lookup = FS.lookupPath(current_path, {
- recurse_count: opts.recurse_count
- });
- current = lookup.node;
- if (count++ > 40) {
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
- }
- }
- }
- return {
- path: current_path,
- node: current
- };
- }),
- getPath: (function(node) {
- var path;
- while (true) {
- if (FS.isRoot(node)) {
- var mount = node.mount.mountpoint;
- if (!path) return mount;
- return mount[mount.length - 1] !== "/" ? mount + "/" + path : mount + path;
- }
- path = path ? node.name + "/" + path : node.name;
- node = node.parent;
- }
- }),
- hashName: (function(parentid, name) {
- var hash = 0;
- for (var i = 0; i < name.length; i++) {
- hash = (hash << 5) - hash + name.charCodeAt(i) | 0;
- }
- return (parentid + hash >>> 0) % FS.nameTable.length;
- }),
- hashAddNode: (function(node) {
- var hash = FS.hashName(node.parent.id, node.name);
- node.name_next = FS.nameTable[hash];
- FS.nameTable[hash] = node;
- }),
- hashRemoveNode: (function(node) {
- var hash = FS.hashName(node.parent.id, node.name);
- if (FS.nameTable[hash] === node) {
- FS.nameTable[hash] = node.name_next;
- } else {
- var current = FS.nameTable[hash];
- while (current) {
- if (current.name_next === node) {
- current.name_next = node.name_next;
- break;
- }
- current = current.name_next;
- }
- }
- }),
- lookupNode: (function(parent, name) {
- var err = FS.mayLookup(parent);
- if (err) {
- throw new FS.ErrnoError(err, parent);
- }
- var hash = FS.hashName(parent.id, name);
- for (var node = FS.nameTable[hash]; node; node = node.name_next) {
- var nodeName = node.name;
- if (node.parent.id === parent.id && nodeName === name) {
- return node;
- }
- }
- return FS.lookup(parent, name);
- }),
- createNode: (function(parent, name, mode, rdev) {
- if (!FS.FSNode) {
- FS.FSNode = (function(parent, name, mode, rdev) {
- if (!parent) {
- parent = this;
- }
- this.parent = parent;
- this.mount = parent.mount;
- this.mounted = null;
- this.id = FS.nextInode++;
- this.name = name;
- this.mode = mode;
- this.node_ops = {};
- this.stream_ops = {};
- this.rdev = rdev;
- });
- FS.FSNode.prototype = {};
- var readMode = 292 | 73;
- var writeMode = 146;
- Object.defineProperties(FS.FSNode.prototype, {
- read: {
- get: (function() {
- return (this.mode & readMode) === readMode;
- }),
- set: (function(val) {
- val ? this.mode |= readMode : this.mode &= ~readMode;
- })
- },
- write: {
- get: (function() {
- return (this.mode & writeMode) === writeMode;
- }),
- set: (function(val) {
- val ? this.mode |= writeMode : this.mode &= ~writeMode;
- })
- },
- isFolder: {
- get: (function() {
- return FS.isDir(this.mode);
- })
- },
- isDevice: {
- get: (function() {
- return FS.isChrdev(this.mode);
- })
- }
- });
- }
- var node = new FS.FSNode(parent, name, mode, rdev);
- FS.hashAddNode(node);
- return node;
- }),
- destroyNode: (function(node) {
- FS.hashRemoveNode(node);
- }),
- isRoot: (function(node) {
- return node === node.parent;
- }),
- isMountpoint: (function(node) {
- return !!node.mounted;
- }),
- isFile: (function(mode) {
- return (mode & 61440) === 32768;
- }),
- isDir: (function(mode) {
- return (mode & 61440) === 16384;
- }),
- isLink: (function(mode) {
- return (mode & 61440) === 40960;
- }),
- isChrdev: (function(mode) {
- return (mode & 61440) === 8192;
- }),
- isBlkdev: (function(mode) {
- return (mode & 61440) === 24576;
- }),
- isFIFO: (function(mode) {
- return (mode & 61440) === 4096;
- }),
- isSocket: (function(mode) {
- return (mode & 49152) === 49152;
- }),
- flagModes: {
- "r": 0,
- "rs": 1052672,
- "r+": 2,
- "w": 577,
- "wx": 705,
- "xw": 705,
- "w+": 578,
- "wx+": 706,
- "xw+": 706,
- "a": 1089,
- "ax": 1217,
- "xa": 1217,
- "a+": 1090,
- "ax+": 1218,
- "xa+": 1218
- },
- modeStringToFlags: (function(str) {
- var flags = FS.flagModes[str];
- if (typeof flags === "undefined") {
- throw new Error("Unknown file open mode: " + str);
- }
- return flags;
- }),
- flagsToPermissionString: (function(flag) {
- var perms = [ "r", "w", "rw" ][flag & 3];
- if (flag & 512) {
- perms += "w";
- }
- return perms;
- }),
- nodePermissions: (function(node, perms) {
- if (FS.ignorePermissions) {
- return 0;
- }
- if (perms.indexOf("r") !== -1 && !(node.mode & 292)) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf("w") !== -1 && !(node.mode & 146)) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf("x") !== -1 && !(node.mode & 73)) {
- return ERRNO_CODES.EACCES;
- }
- return 0;
- }),
- mayLookup: (function(dir) {
- var err = FS.nodePermissions(dir, "x");
- if (err) return err;
- if (!dir.node_ops.lookup) return ERRNO_CODES.EACCES;
- return 0;
- }),
- mayCreate: (function(dir, name) {
- try {
- var node = FS.lookupNode(dir, name);
- return ERRNO_CODES.EEXIST;
- } catch (e) {}
- return FS.nodePermissions(dir, "wx");
- }),
- mayDelete: (function(dir, name, isdir) {
- var node;
- try {
- node = FS.lookupNode(dir, name);
- } catch (e) {
- return e.errno;
- }
- var err = FS.nodePermissions(dir, "wx");
- if (err) {
- return err;
- }
- if (isdir) {
- if (!FS.isDir(node.mode)) {
- return ERRNO_CODES.ENOTDIR;
- }
- if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
- return ERRNO_CODES.EBUSY;
- }
- } else {
- if (FS.isDir(node.mode)) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return 0;
- }),
- mayOpen: (function(node, flags) {
- if (!node) {
- return ERRNO_CODES.ENOENT;
- }
- if (FS.isLink(node.mode)) {
- return ERRNO_CODES.ELOOP;
- } else if (FS.isDir(node.mode)) {
- if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
- }),
- MAX_OPEN_FDS: 4096,
- nextfd: (function(fd_start, fd_end) {
- fd_start = fd_start || 0;
- fd_end = fd_end || FS.MAX_OPEN_FDS;
- for (var fd = fd_start; fd <= fd_end; fd++) {
- if (!FS.streams[fd]) {
- return fd;
- }
- }
- throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
- }),
- getStream: (function(fd) {
- return FS.streams[fd];
- }),
- createStream: (function(stream, fd_start, fd_end) {
- if (!FS.FSStream) {
- FS.FSStream = (function() {});
- FS.FSStream.prototype = {};
- Object.defineProperties(FS.FSStream.prototype, {
- object: {
- get: (function() {
- return this.node;
- }),
- set: (function(val) {
- this.node = val;
- })
- },
- isRead: {
- get: (function() {
- return (this.flags & 2097155) !== 1;
- })
- },
- isWrite: {
- get: (function() {
- return (this.flags & 2097155) !== 0;
- })
- },
- isAppend: {
- get: (function() {
- return this.flags & 1024;
- })
- }
- });
- }
- var newStream = new FS.FSStream;
- for (var p in stream) {
- newStream[p] = stream[p];
- }
- stream = newStream;
- var fd = FS.nextfd(fd_start, fd_end);
- stream.fd = fd;
- FS.streams[fd] = stream;
- return stream;
- }),
- closeStream: (function(fd) {
- FS.streams[fd] = null;
- }),
- chrdev_stream_ops: {
- open: (function(stream) {
- var device = FS.getDevice(stream.node.rdev);
- stream.stream_ops = device.stream_ops;
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- }),
- llseek: (function() {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- })
- },
- major: (function(dev) {
- return dev >> 8;
- }),
- minor: (function(dev) {
- return dev & 255;
- }),
- makedev: (function(ma, mi) {
- return ma << 8 | mi;
- }),
- registerDevice: (function(dev, ops) {
- FS.devices[dev] = {
- stream_ops: ops
- };
- }),
- getDevice: (function(dev) {
- return FS.devices[dev];
- }),
- getMounts: (function(mount) {
- var mounts = [];
- var check = [ mount ];
- while (check.length) {
- var m = check.pop();
- mounts.push(m);
- check.push.apply(check, m.mounts);
- }
- return mounts;
- }),
- syncfs: (function(populate, callback) {
- if (typeof populate === "function") {
- callback = populate;
- populate = false;
- }
- FS.syncFSRequests++;
- if (FS.syncFSRequests > 1) {
- console.log("warning: " + FS.syncFSRequests + " FS.syncfs operations in flight at once, probably just doing extra work");
- }
- var mounts = FS.getMounts(FS.root.mount);
- var completed = 0;
- function doCallback(err) {
- assert(FS.syncFSRequests > 0);
- FS.syncFSRequests--;
- return callback(err);
- }
- function done(err) {
- if (err) {
- if (!done.errored) {
- done.errored = true;
- return doCallback(err);
- }
- return;
- }
- if (++completed >= mounts.length) {
- doCallback(null);
- }
- }
- mounts.forEach((function(mount) {
- if (!mount.type.syncfs) {
- return done(null);
- }
- mount.type.syncfs(mount, populate, done);
- }));
- }),
- mount: (function(type, opts, mountpoint) {
- var root = mountpoint === "/";
- var pseudo = !mountpoint;
- var node;
- if (root && FS.root) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- } else if (!root && !pseudo) {
- var lookup = FS.lookupPath(mountpoint, {
- follow_mount: false
- });
- mountpoint = lookup.path;
- node = lookup.node;
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- if (!FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- }
- var mount = {
- type: type,
- opts: opts,
- mountpoint: mountpoint,
- mounts: []
- };
- var mountRoot = type.mount(mount);
- mountRoot.mount = mount;
- mount.root = mountRoot;
- if (root) {
- FS.root = mountRoot;
- } else if (node) {
- node.mounted = mount;
- if (node.mount) {
- node.mount.mounts.push(mount);
- }
- }
- return mountRoot;
- }),
- unmount: (function(mountpoint) {
- var lookup = FS.lookupPath(mountpoint, {
- follow_mount: false
- });
- if (!FS.isMountpoint(lookup.node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var node = lookup.node;
- var mount = node.mounted;
- var mounts = FS.getMounts(mount);
- Object.keys(FS.nameTable).forEach((function(hash) {
- var current = FS.nameTable[hash];
- while (current) {
- var next = current.name_next;
- if (mounts.indexOf(current.mount) !== -1) {
- FS.destroyNode(current);
- }
- current = next;
- }
- }));
- node.mounted = null;
- var idx = node.mount.mounts.indexOf(mount);
- assert(idx !== -1);
- node.mount.mounts.splice(idx, 1);
- }),
- lookup: (function(parent, name) {
- return parent.node_ops.lookup(parent, name);
- }),
- mknod: (function(path, mode, dev) {
- var lookup = FS.lookupPath(path, {
- parent: true
- });
- var parent = lookup.node;
- var name = PATH.basename(path);
- if (!name || name === "." || name === "..") {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var err = FS.mayCreate(parent, name);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.mknod) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return parent.node_ops.mknod(parent, name, mode, dev);
- }),
- create: (function(path, mode) {
- mode = mode !== undefined ? mode : 438;
- mode &= 4095;
- mode |= 32768;
- return FS.mknod(path, mode, 0);
- }),
- mkdir: (function(path, mode) {
- mode = mode !== undefined ? mode : 511;
- mode &= 511 | 512;
- mode |= 16384;
- return FS.mknod(path, mode, 0);
- }),
- mkdirTree: (function(path, mode) {
- var dirs = path.split("/");
- var d = "";
- for (var i = 0; i < dirs.length; ++i) {
- if (!dirs[i]) continue;
- d += "/" + dirs[i];
- try {
- FS.mkdir(d, mode);
- } catch (e) {
- if (e.errno != ERRNO_CODES.EEXIST) throw e;
- }
- }
- }),
- mkdev: (function(path, mode, dev) {
- if (typeof dev === "undefined") {
- dev = mode;
- mode = 438;
- }
- mode |= 8192;
- return FS.mknod(path, mode, dev);
- }),
- symlink: (function(oldpath, newpath) {
- if (!PATH.resolve(oldpath)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- var lookup = FS.lookupPath(newpath, {
- parent: true
- });
- var parent = lookup.node;
- if (!parent) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- var newname = PATH.basename(newpath);
- var err = FS.mayCreate(parent, newname);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.symlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return parent.node_ops.symlink(parent, newname, oldpath);
- }),
- rename: (function(old_path, new_path) {
- var old_dirname = PATH.dirname(old_path);
- var new_dirname = PATH.dirname(new_path);
- var old_name = PATH.basename(old_path);
- var new_name = PATH.basename(new_path);
- var lookup, old_dir, new_dir;
- try {
- lookup = FS.lookupPath(old_path, {
- parent: true
- });
- old_dir = lookup.node;
- lookup = FS.lookupPath(new_path, {
- parent: true
- });
- new_dir = lookup.node;
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- if (!old_dir || !new_dir) throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- if (old_dir.mount !== new_dir.mount) {
- throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
- }
- var old_node = FS.lookupNode(old_dir, old_name);
- var relative = PATH.relative(old_path, new_dirname);
- if (relative.charAt(0) !== ".") {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- relative = PATH.relative(new_path, old_dirname);
- if (relative.charAt(0) !== ".") {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- var new_node;
- try {
- new_node = FS.lookupNode(new_dir, new_name);
- } catch (e) {}
- if (old_node === new_node) {
- return;
- }
- var isdir = FS.isDir(old_node.mode);
- var err = FS.mayDelete(old_dir, old_name, isdir);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- err = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!old_dir.node_ops.rename) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(old_node) || new_node && FS.isMountpoint(new_node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- if (new_dir !== old_dir) {
- err = FS.nodePermissions(old_dir, "w");
- if (err) {
- throw new FS.ErrnoError(err);
- }
- }
- try {
- if (FS.trackingDelegate["willMovePath"]) {
- FS.trackingDelegate["willMovePath"](old_path, new_path);
- }
- } catch (e) {
- console.log("FS.trackingDelegate['willMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message);
- }
- FS.hashRemoveNode(old_node);
- try {
- old_dir.node_ops.rename(old_node, new_dir, new_name);
- } catch (e) {
- throw e;
- } finally {
- FS.hashAddNode(old_node);
- }
- try {
- if (FS.trackingDelegate["onMovePath"]) FS.trackingDelegate["onMovePath"](old_path, new_path);
- } catch (e) {
- console.log("FS.trackingDelegate['onMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message);
- }
- }),
- rmdir: (function(path) {
- var lookup = FS.lookupPath(path, {
- parent: true
- });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var node = FS.lookupNode(parent, name);
- var err = FS.mayDelete(parent, name, true);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.rmdir) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- try {
- if (FS.trackingDelegate["willDeletePath"]) {
- FS.trackingDelegate["willDeletePath"](path);
- }
- } catch (e) {
- console.log("FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message);
- }
- parent.node_ops.rmdir(parent, name);
- FS.destroyNode(node);
- try {
- if (FS.trackingDelegate["onDeletePath"]) FS.trackingDelegate["onDeletePath"](path);
- } catch (e) {
- console.log("FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message);
- }
- }),
- readdir: (function(path) {
- var lookup = FS.lookupPath(path, {
- follow: true
- });
- var node = lookup.node;
- if (!node.node_ops.readdir) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- return node.node_ops.readdir(node);
- }),
- unlink: (function(path) {
- var lookup = FS.lookupPath(path, {
- parent: true
- });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var node = FS.lookupNode(parent, name);
- var err = FS.mayDelete(parent, name, false);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.unlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- try {
- if (FS.trackingDelegate["willDeletePath"]) {
- FS.trackingDelegate["willDeletePath"](path);
- }
- } catch (e) {
- console.log("FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message);
- }
- parent.node_ops.unlink(parent, name);
- FS.destroyNode(node);
- try {
- if (FS.trackingDelegate["onDeletePath"]) FS.trackingDelegate["onDeletePath"](path);
- } catch (e) {
- console.log("FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message);
- }
- }),
- readlink: (function(path) {
- var lookup = FS.lookupPath(path);
- var link = lookup.node;
- if (!link) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- if (!link.node_ops.readlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return PATH.resolve(FS.getPath(link.parent), link.node_ops.readlink(link));
- }),
- stat: (function(path, dontFollow) {
- var lookup = FS.lookupPath(path, {
- follow: !dontFollow
- });
- var node = lookup.node;
- if (!node) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- if (!node.node_ops.getattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return node.node_ops.getattr(node);
- }),
- lstat: (function(path) {
- return FS.stat(path, true);
- }),
- chmod: (function(path, mode, dontFollow) {
- var node;
- if (typeof path === "string") {
- var lookup = FS.lookupPath(path, {
- follow: !dontFollow
- });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- node.node_ops.setattr(node, {
- mode: mode & 4095 | node.mode & ~4095,
- timestamp: Date.now()
- });
- }),
- lchmod: (function(path, mode) {
- FS.chmod(path, mode, true);
- }),
- fchmod: (function(fd, mode) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- FS.chmod(stream.node, mode);
- }),
- chown: (function(path, uid, gid, dontFollow) {
- var node;
- if (typeof path === "string") {
- var lookup = FS.lookupPath(path, {
- follow: !dontFollow
- });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- node.node_ops.setattr(node, {
- timestamp: Date.now()
- });
- }),
- lchown: (function(path, uid, gid) {
- FS.chown(path, uid, gid, true);
- }),
- fchown: (function(fd, uid, gid) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- FS.chown(stream.node, uid, gid);
- }),
- truncate: (function(path, len) {
- if (len < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var node;
- if (typeof path === "string") {
- var lookup = FS.lookupPath(path, {
- follow: true
- });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!FS.isFile(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var err = FS.nodePermissions(node, "w");
- if (err) {
- throw new FS.ErrnoError(err);
- }
- node.node_ops.setattr(node, {
- size: len,
- timestamp: Date.now()
- });
- }),
- ftruncate: (function(fd, len) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if ((stream.flags & 2097155) === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- FS.truncate(stream.node, len);
- }),
- utime: (function(path, atime, mtime) {
- var lookup = FS.lookupPath(path, {
- follow: true
- });
- var node = lookup.node;
- node.node_ops.setattr(node, {
- timestamp: Math.max(atime, mtime)
- });
- }),
- open: (function(path, flags, mode, fd_start, fd_end) {
- if (path === "") {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- flags = typeof flags === "string" ? FS.modeStringToFlags(flags) : flags;
- mode = typeof mode === "undefined" ? 438 : mode;
- if (flags & 64) {
- mode = mode & 4095 | 32768;
- } else {
- mode = 0;
- }
- var node;
- if (typeof path === "object") {
- node = path;
- } else {
- path = PATH.normalize(path);
- try {
- var lookup = FS.lookupPath(path, {
- follow: !(flags & 131072)
- });
- node = lookup.node;
- } catch (e) {}
- }
- var created = false;
- if (flags & 64) {
- if (node) {
- if (flags & 128) {
- throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
- }
- } else {
- node = FS.mknod(path, mode, 0);
- created = true;
- }
- }
- if (!node) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- if (FS.isChrdev(node.mode)) {
- flags &= ~512;
- }
- if (flags & 65536 && !FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- if (!created) {
- var err = FS.mayOpen(node, flags);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- }
- if (flags & 512) {
- FS.truncate(node, 0);
- }
- flags &= ~(128 | 512);
- var stream = FS.createStream({
- node: node,
- path: FS.getPath(node),
- flags: flags,
- seekable: true,
- position: 0,
- stream_ops: node.stream_ops,
- ungotten: [],
- error: false
- }, fd_start, fd_end);
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- if (Module["logReadFiles"] && !(flags & 1)) {
- if (!FS.readFiles) FS.readFiles = {};
- if (!(path in FS.readFiles)) {
- FS.readFiles[path] = 1;
- Module["printErr"]("read file: " + path);
- }
- }
- try {
- if (FS.trackingDelegate["onOpenFile"]) {
- var trackingFlags = 0;
- if ((flags & 2097155) !== 1) {
- trackingFlags |= FS.tracking.openFlags.READ;
- }
- if ((flags & 2097155) !== 0) {
- trackingFlags |= FS.tracking.openFlags.WRITE;
- }
- FS.trackingDelegate["onOpenFile"](path, trackingFlags);
- }
- } catch (e) {
- console.log("FS.trackingDelegate['onOpenFile']('" + path + "', flags) threw an exception: " + e.message);
- }
- return stream;
- }),
- close: (function(stream) {
- if (FS.isClosed(stream)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (stream.getdents) stream.getdents = null;
- try {
- if (stream.stream_ops.close) {
- stream.stream_ops.close(stream);
- }
- } catch (e) {
- throw e;
- } finally {
- FS.closeStream(stream.fd);
- }
- stream.fd = null;
- }),
- isClosed: (function(stream) {
- return stream.fd === null;
- }),
- llseek: (function(stream, offset, whence) {
- if (FS.isClosed(stream)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (!stream.seekable || !stream.stream_ops.llseek) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- stream.position = stream.stream_ops.llseek(stream, offset, whence);
- stream.ungotten = [];
- return stream.position;
- }),
- read: (function(stream, buffer, offset, length, position) {
- if (length < 0 || position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if (FS.isClosed(stream)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if ((stream.flags & 2097155) === 1) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!stream.stream_ops.read) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var seeking = typeof position !== "undefined";
- if (!seeking) {
- position = stream.position;
- } else if (!stream.seekable) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
- if (!seeking) stream.position += bytesRead;
- return bytesRead;
- }),
- write: (function(stream, buffer, offset, length, position, canOwn) {
- if (length < 0 || position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if (FS.isClosed(stream)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if ((stream.flags & 2097155) === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!stream.stream_ops.write) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if (stream.flags & 1024) {
- FS.llseek(stream, 0, 2);
- }
- var seeking = typeof position !== "undefined";
- if (!seeking) {
- position = stream.position;
- } else if (!stream.seekable) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
- if (!seeking) stream.position += bytesWritten;
- try {
- if (stream.path && FS.trackingDelegate["onWriteToFile"]) FS.trackingDelegate["onWriteToFile"](stream.path);
- } catch (e) {
- console.log("FS.trackingDelegate['onWriteToFile']('" + path + "') threw an exception: " + e.message);
- }
- return bytesWritten;
- }),
- allocate: (function(stream, offset, length) {
- if (FS.isClosed(stream)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (offset < 0 || length <= 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & 2097155) === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- if (!stream.stream_ops.allocate) {
- throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
- }
- stream.stream_ops.allocate(stream, offset, length);
- }),
- mmap: (function(stream, buffer, offset, length, position, prot, flags) {
- if ((stream.flags & 2097155) === 1) {
- throw new FS.ErrnoError(ERRNO_CODES.EACCES);
- }
- if (!stream.stream_ops.mmap) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
- }),
- msync: (function(stream, buffer, offset, length, mmapFlags) {
- if (!stream || !stream.stream_ops.msync) {
- return 0;
- }
- return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);
- }),
- munmap: (function(stream) {
- return 0;
- }),
- ioctl: (function(stream, cmd, arg) {
- if (!stream.stream_ops.ioctl) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
- }
- return stream.stream_ops.ioctl(stream, cmd, arg);
- }),
- readFile: (function(path, opts) {
- opts = opts || {};
- opts.flags = opts.flags || "r";
- opts.encoding = opts.encoding || "binary";
- if (opts.encoding !== "utf8" && opts.encoding !== "binary") {
- throw new Error('Invalid encoding type "' + opts.encoding + '"');
- }
- var ret;
- var stream = FS.open(path, opts.flags);
- var stat = FS.stat(path);
- var length = stat.size;
- var buf = new Uint8Array(length);
- FS.read(stream, buf, 0, length, 0);
- if (opts.encoding === "utf8") {
- ret = UTF8ArrayToString(buf, 0);
- } else if (opts.encoding === "binary") {
- ret = buf;
- }
- FS.close(stream);
- return ret;
- }),
- writeFile: (function(path, data, opts) {
- opts = opts || {};
- opts.flags = opts.flags || "w";
- var stream = FS.open(path, opts.flags, opts.mode);
- if (typeof data === "string") {
- var buf = new Uint8Array(lengthBytesUTF8(data) + 1);
- var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);
- FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn);
- } else if (ArrayBuffer.isView(data)) {
- FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
- } else {
- throw new Error("Unsupported data type");
- }
- FS.close(stream);
- }),
- cwd: (function() {
- return FS.currentPath;
- }),
- chdir: (function(path) {
- var lookup = FS.lookupPath(path, {
- follow: true
- });
- if (lookup.node === null) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- if (!FS.isDir(lookup.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- var err = FS.nodePermissions(lookup.node, "x");
- if (err) {
- throw new FS.ErrnoError(err);
- }
- FS.currentPath = lookup.path;
- }),
- createDefaultDirectories: (function() {
- FS.mkdir("/tmp");
- FS.mkdir("/home");
- FS.mkdir("/home/web_user");
- }),
- createDefaultDevices: (function() {
- FS.mkdir("/dev");
- FS.registerDevice(FS.makedev(1, 3), {
- read: (function() {
- return 0;
- }),
- write: (function(stream, buffer, offset, length, pos) {
- return length;
- })
- });
- FS.mkdev("/dev/null", FS.makedev(1, 3));
- TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
- TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
- FS.mkdev("/dev/tty", FS.makedev(5, 0));
- FS.mkdev("/dev/tty1", FS.makedev(6, 0));
- var random_device;
- if (typeof crypto !== "undefined") {
- var randomBuffer = new Uint8Array(1);
- random_device = (function() {
- crypto.getRandomValues(randomBuffer);
- return randomBuffer[0];
- });
- } else if (ENVIRONMENT_IS_NODE) {
- random_device = (function() {
- return require("crypto")["randomBytes"](1)[0];
- });
- } else {
- random_device = (function() {
- return Math.random() * 256 | 0;
- });
- }
- FS.createDevice("/dev", "random", random_device);
- FS.createDevice("/dev", "urandom", random_device);
- FS.mkdir("/dev/shm");
- FS.mkdir("/dev/shm/tmp");
- }),
- createSpecialDirectories: (function() {
- FS.mkdir("/proc");
- FS.mkdir("/proc/self");
- FS.mkdir("/proc/self/fd");
- FS.mount({
- mount: (function() {
- var node = FS.createNode("/proc/self", "fd", 16384 | 511, 73);
- node.node_ops = {
- lookup: (function(parent, name) {
- var fd = +name;
- var stream = FS.getStream(fd);
- if (!stream) throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- var ret = {
- parent: null,
- mount: {
- mountpoint: "fake"
- },
- node_ops: {
- readlink: (function() {
- return stream.path;
- })
- }
- };
- ret.parent = ret;
- return ret;
- })
- };
- return node;
- })
- }, {}, "/proc/self/fd");
- }),
- createStandardStreams: (function() {
- if (Module["stdin"]) {
- FS.createDevice("/dev", "stdin", Module["stdin"]);
- } else {
- FS.symlink("/dev/tty", "/dev/stdin");
- }
- if (Module["stdout"]) {
- FS.createDevice("/dev", "stdout", null, Module["stdout"]);
- } else {
- FS.symlink("/dev/tty", "/dev/stdout");
- }
- if (Module["stderr"]) {
- FS.createDevice("/dev", "stderr", null, Module["stderr"]);
- } else {
- FS.symlink("/dev/tty1", "/dev/stderr");
- }
- var stdin = FS.open("/dev/stdin", "r");
- assert(stdin.fd === 0, "invalid handle for stdin (" + stdin.fd + ")");
- var stdout = FS.open("/dev/stdout", "w");
- assert(stdout.fd === 1, "invalid handle for stdout (" + stdout.fd + ")");
- var stderr = FS.open("/dev/stderr", "w");
- assert(stderr.fd === 2, "invalid handle for stderr (" + stderr.fd + ")");
- }),
- ensureErrnoError: (function() {
- if (FS.ErrnoError) return;
- FS.ErrnoError = function ErrnoError(errno, node) {
- this.node = node;
- this.setErrno = (function(errno) {
- this.errno = errno;
- for (var key in ERRNO_CODES) {
- if (ERRNO_CODES[key] === errno) {
- this.code = key;
- break;
- }
- }
- });
- this.setErrno(errno);
- this.message = ERRNO_MESSAGES[errno];
- if (this.stack) Object.defineProperty(this, "stack", {
- value: (new Error).stack,
- writable: true
- });
- };
- FS.ErrnoError.prototype = new Error;
- FS.ErrnoError.prototype.constructor = FS.ErrnoError;
- [ ERRNO_CODES.ENOENT ].forEach((function(code) {
- FS.genericErrors[code] = new FS.ErrnoError(code);
- FS.genericErrors[code].stack = "<generic error, no stack>";
- }));
- }),
- staticInit: (function() {
- FS.ensureErrnoError();
- FS.nameTable = new Array(4096);
- FS.mount(MEMFS, {}, "/");
- FS.createDefaultDirectories();
- FS.createDefaultDevices();
- FS.createSpecialDirectories();
- FS.filesystems = {
- "MEMFS": MEMFS,
- "IDBFS": IDBFS,
- "NODEFS": NODEFS,
- "WORKERFS": WORKERFS
- };
- }),
- init: (function(input, output, error) {
- assert(!FS.init.initialized, "FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)");
- FS.init.initialized = true;
- FS.ensureErrnoError();
- Module["stdin"] = input || Module["stdin"];
- Module["stdout"] = output || Module["stdout"];
- Module["stderr"] = error || Module["stderr"];
- FS.createStandardStreams();
- }),
- quit: (function() {
- FS.init.initialized = false;
- var fflush = Module["_fflush"];
- if (fflush) fflush(0);
- for (var i = 0; i < FS.streams.length; i++) {
- var stream = FS.streams[i];
- if (!stream) {
- continue;
- }
- FS.close(stream);
- }
- }),
- getMode: (function(canRead, canWrite) {
- var mode = 0;
- if (canRead) mode |= 292 | 73;
- if (canWrite) mode |= 146;
- return mode;
- }),
- joinPath: (function(parts, forceRelative) {
- var path = PATH.join.apply(null, parts);
- if (forceRelative && path[0] == "/") path = path.substr(1);
- return path;
- }),
- absolutePath: (function(relative, base) {
- return PATH.resolve(base, relative);
- }),
- standardizePath: (function(path) {
- return PATH.normalize(path);
- }),
- findObject: (function(path, dontResolveLastLink) {
- var ret = FS.analyzePath(path, dontResolveLastLink);
- if (ret.exists) {
- return ret.object;
- } else {
- ___setErrNo(ret.error);
- return null;
- }
- }),
- analyzePath: (function(path, dontResolveLastLink) {
- try {
- var lookup = FS.lookupPath(path, {
- follow: !dontResolveLastLink
- });
- path = lookup.path;
- } catch (e) {}
- var ret = {
- isRoot: false,
- exists: false,
- error: 0,
- name: null,
- path: null,
- object: null,
- parentExists: false,
- parentPath: null,
- parentObject: null
- };
- try {
- var lookup = FS.lookupPath(path, {
- parent: true
- });
- ret.parentExists = true;
- ret.parentPath = lookup.path;
- ret.parentObject = lookup.node;
- ret.name = PATH.basename(path);
- lookup = FS.lookupPath(path, {
- follow: !dontResolveLastLink
- });
- ret.exists = true;
- ret.path = lookup.path;
- ret.object = lookup.node;
- ret.name = lookup.node.name;
- ret.isRoot = lookup.path === "/";
- } catch (e) {
- ret.error = e.errno;
- }
- return ret;
- }),
- createFolder: (function(parent, name, canRead, canWrite) {
- var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return FS.mkdir(path, mode);
- }),
- createPath: (function(parent, path, canRead, canWrite) {
- parent = typeof parent === "string" ? parent : FS.getPath(parent);
- var parts = path.split("/").reverse();
- while (parts.length) {
- var part = parts.pop();
- if (!part) continue;
- var current = PATH.join2(parent, part);
- try {
- FS.mkdir(current);
- } catch (e) {}
- parent = current;
- }
- return current;
- }),
- createFile: (function(parent, name, properties, canRead, canWrite) {
- var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return FS.create(path, mode);
- }),
- createDataFile: (function(parent, name, data, canRead, canWrite, canOwn) {
- var path = name ? PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name) : parent;
- var mode = FS.getMode(canRead, canWrite);
- var node = FS.create(path, mode);
- if (data) {
- if (typeof data === "string") {
- var arr = new Array(data.length);
- for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
- data = arr;
- }
- FS.chmod(node, mode | 146);
- var stream = FS.open(node, "w");
- FS.write(stream, data, 0, data.length, 0, canOwn);
- FS.close(stream);
- FS.chmod(node, mode);
- }
- return node;
- }),
- createDevice: (function(parent, name, input, output) {
- var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(!!input, !!output);
- if (!FS.createDevice.major) FS.createDevice.major = 64;
- var dev = FS.makedev(FS.createDevice.major++, 0);
- FS.registerDevice(dev, {
- open: (function(stream) {
- stream.seekable = false;
- }),
- close: (function(stream) {
- if (output && output.buffer && output.buffer.length) {
- output(10);
- }
- }),
- read: (function(stream, buffer, offset, length, pos) {
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = input();
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset + i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- }),
- write: (function(stream, buffer, offset, length, pos) {
- for (var i = 0; i < length; i++) {
- try {
- output(buffer[offset + i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- })
- });
- return FS.mkdev(path, mode, dev);
- }),
- createLink: (function(parent, name, target, canRead, canWrite) {
- var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name);
- return FS.symlink(target, path);
- }),
- forceLoadFile: (function(obj) {
- if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
- var success = true;
- if (typeof XMLHttpRequest !== "undefined") {
- throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
- } else if (Module["read"]) {
- try {
- obj.contents = intArrayFromString(Module["read"](obj.url), true);
- obj.usedBytes = obj.contents.length;
- } catch (e) {
- success = false;
- }
- } else {
- throw new Error("Cannot load without read() or XMLHttpRequest.");
- }
- if (!success) ___setErrNo(ERRNO_CODES.EIO);
- return success;
- }),
- createLazyFile: (function(parent, name, url, canRead, canWrite) {
- function LazyUint8Array() {
- this.lengthKnown = false;
- this.chunks = [];
- }
- LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
- if (idx > this.length - 1 || idx < 0) {
- return undefined;
- }
- var chunkOffset = idx % this.chunkSize;
- var chunkNum = idx / this.chunkSize | 0;
- return this.getter(chunkNum)[chunkOffset];
- };
- LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
- this.getter = getter;
- };
- LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
- var xhr = new XMLHttpRequest;
- xhr.open("HEAD", url, false);
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- var datalength = Number(xhr.getResponseHeader("Content-length"));
- var header;
- var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
- var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
- var chunkSize = 1024 * 1024;
- if (!hasByteServing) chunkSize = datalength;
- var doXHR = (function(from, to) {
- if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
- if (to > datalength - 1) throw new Error("only " + datalength + " bytes available! programmer error!");
- var xhr = new XMLHttpRequest;
- xhr.open("GET", url, false);
- if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
- if (typeof Uint8Array != "undefined") xhr.responseType = "arraybuffer";
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType("text/plain; charset=x-user-defined");
- }
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- if (xhr.response !== undefined) {
- return new Uint8Array(xhr.response || []);
- } else {
- return intArrayFromString(xhr.responseText || "", true);
- }
- });
- var lazyArray = this;
- lazyArray.setDataGetter((function(chunkNum) {
- var start = chunkNum * chunkSize;
- var end = (chunkNum + 1) * chunkSize - 1;
- end = Math.min(end, datalength - 1);
- if (typeof lazyArray.chunks[chunkNum] === "undefined") {
- lazyArray.chunks[chunkNum] = doXHR(start, end);
- }
- if (typeof lazyArray.chunks[chunkNum] === "undefined") throw new Error("doXHR failed!");
- return lazyArray.chunks[chunkNum];
- }));
- if (usesGzip || !datalength) {
- chunkSize = datalength = 1;
- datalength = this.getter(0).length;
- chunkSize = datalength;
- console.log("LazyFiles on gzip forces download of the whole file when length is accessed");
- }
- this._length = datalength;
- this._chunkSize = chunkSize;
- this.lengthKnown = true;
- };
- if (typeof XMLHttpRequest !== "undefined") {
- if (!ENVIRONMENT_IS_WORKER) throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";
- var lazyArray = new LazyUint8Array;
- Object.defineProperties(lazyArray, {
- length: {
- get: (function() {
- if (!this.lengthKnown) {
- this.cacheLength();
- }
- return this._length;
- })
- },
- chunkSize: {
- get: (function() {
- if (!this.lengthKnown) {
- this.cacheLength();
- }
- return this._chunkSize;
- })
- }
- });
- var properties = {
- isDevice: false,
- contents: lazyArray
- };
- } else {
- var properties = {
- isDevice: false,
- url: url
- };
- }
- var node = FS.createFile(parent, name, properties, canRead, canWrite);
- if (properties.contents) {
- node.contents = properties.contents;
- } else if (properties.url) {
- node.contents = null;
- node.url = properties.url;
- }
- Object.defineProperties(node, {
- usedBytes: {
- get: (function() {
- return this.contents.length;
- })
- }
- });
- var stream_ops = {};
- var keys = Object.keys(node.stream_ops);
- keys.forEach((function(key) {
- var fn = node.stream_ops[key];
- stream_ops[key] = function forceLoadLazyFile() {
- if (!FS.forceLoadFile(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- return fn.apply(null, arguments);
- };
- }));
- stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
- if (!FS.forceLoadFile(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- var contents = stream.node.contents;
- if (position >= contents.length) return 0;
- var size = Math.min(contents.length - position, length);
- assert(size >= 0);
- if (contents.slice) {
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents[position + i];
- }
- } else {
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents.get(position + i);
- }
- }
- return size;
- };
- node.stream_ops = stream_ops;
- return node;
- }),
- createPreloadedFile: (function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) {
- Browser.init();
- var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
- var dep = getUniqueRunDependency("cp " + fullname);
- function processData(byteArray) {
- function finish(byteArray) {
- if (preFinish) preFinish();
- if (!dontCreateFile) {
- FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
- }
- if (onload) onload();
- removeRunDependency(dep);
- }
- var handled = false;
- Module["preloadPlugins"].forEach((function(plugin) {
- if (handled) return;
- if (plugin["canHandle"](fullname)) {
- plugin["handle"](byteArray, fullname, finish, (function() {
- if (onerror) onerror();
- removeRunDependency(dep);
- }));
- handled = true;
- }
- }));
- if (!handled) finish(byteArray);
- }
- addRunDependency(dep);
- if (typeof url == "string") {
- Browser.asyncLoad(url, (function(byteArray) {
- processData(byteArray);
- }), onerror);
- } else {
- processData(url);
- }
- }),
- indexedDB: (function() {
- return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
- }),
- DB_NAME: (function() {
- return "EM_FS_" + window.location.pathname;
- }),
- DB_VERSION: 20,
- DB_STORE_NAME: "FILE_DATA",
- saveFilesToDB: (function(paths, onload, onerror) {
- onload = onload || (function() {});
- onerror = onerror || (function() {});
- var indexedDB = FS.indexedDB();
- try {
- var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
- } catch (e) {
- return onerror(e);
- }
- openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
- console.log("creating db");
- var db = openRequest.result;
- db.createObjectStore(FS.DB_STORE_NAME);
- };
- openRequest.onsuccess = function openRequest_onsuccess() {
- var db = openRequest.result;
- var transaction = db.transaction([ FS.DB_STORE_NAME ], "readwrite");
- var files = transaction.objectStore(FS.DB_STORE_NAME);
- var ok = 0, fail = 0, total = paths.length;
- function finish() {
- if (fail == 0) onload(); else onerror();
- }
- paths.forEach((function(path) {
- var putRequest = files.put(FS.analyzePath(path).object.contents, path);
- putRequest.onsuccess = function putRequest_onsuccess() {
- ok++;
- if (ok + fail == total) finish();
- };
- putRequest.onerror = function putRequest_onerror() {
- fail++;
- if (ok + fail == total) finish();
- };
- }));
- transaction.onerror = onerror;
- };
- openRequest.onerror = onerror;
- }),
- loadFilesFromDB: (function(paths, onload, onerror) {
- onload = onload || (function() {});
- onerror = onerror || (function() {});
- var indexedDB = FS.indexedDB();
- try {
- var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
- } catch (e) {
- return onerror(e);
- }
- openRequest.onupgradeneeded = onerror;
- openRequest.onsuccess = function openRequest_onsuccess() {
- var db = openRequest.result;
- try {
- var transaction = db.transaction([ FS.DB_STORE_NAME ], "readonly");
- } catch (e) {
- onerror(e);
- return;
- }
- var files = transaction.objectStore(FS.DB_STORE_NAME);
- var ok = 0, fail = 0, total = paths.length;
- function finish() {
- if (fail == 0) onload(); else onerror();
- }
- paths.forEach((function(path) {
- var getRequest = files.get(path);
- getRequest.onsuccess = function getRequest_onsuccess() {
- if (FS.analyzePath(path).exists) {
- FS.unlink(path);
- }
- FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
- ok++;
- if (ok + fail == total) finish();
- };
- getRequest.onerror = function getRequest_onerror() {
- fail++;
- if (ok + fail == total) finish();
- };
- }));
- transaction.onerror = onerror;
- };
- openRequest.onerror = onerror;
- })
-};
-var SYSCALLS = {
- DEFAULT_POLLMASK: 5,
- mappings: {},
- umask: 511,
- calculateAt: (function(dirfd, path) {
- if (path[0] !== "/") {
- var dir;
- if (dirfd === -100) {
- dir = FS.cwd();
- } else {
- var dirstream = FS.getStream(dirfd);
- if (!dirstream) throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- dir = dirstream.path;
- }
- path = PATH.join2(dir, path);
- }
- return path;
- }),
- doStat: (function(func, path, buf) {
- try {
- var stat = func(path);
- } catch (e) {
- if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {
- return -ERRNO_CODES.ENOTDIR;
- }
- throw e;
- }
- HEAP32[buf >> 2] = stat.dev;
- HEAP32[buf + 4 >> 2] = 0;
- HEAP32[buf + 8 >> 2] = stat.ino;
- HEAP32[buf + 12 >> 2] = stat.mode;
- HEAP32[buf + 16 >> 2] = stat.nlink;
- HEAP32[buf + 20 >> 2] = stat.uid;
- HEAP32[buf + 24 >> 2] = stat.gid;
- HEAP32[buf + 28 >> 2] = stat.rdev;
- HEAP32[buf + 32 >> 2] = 0;
- HEAP32[buf + 36 >> 2] = stat.size;
- HEAP32[buf + 40 >> 2] = 4096;
- HEAP32[buf + 44 >> 2] = stat.blocks;
- HEAP32[buf + 48 >> 2] = stat.atime.getTime() / 1e3 | 0;
- HEAP32[buf + 52 >> 2] = 0;
- HEAP32[buf + 56 >> 2] = stat.mtime.getTime() / 1e3 | 0;
- HEAP32[buf + 60 >> 2] = 0;
- HEAP32[buf + 64 >> 2] = stat.ctime.getTime() / 1e3 | 0;
- HEAP32[buf + 68 >> 2] = 0;
- HEAP32[buf + 72 >> 2] = stat.ino;
- return 0;
- }),
- doMsync: (function(addr, stream, len, flags) {
- var buffer = new Uint8Array(HEAPU8.subarray(addr, addr + len));
- FS.msync(stream, buffer, 0, len, flags);
- }),
- doMkdir: (function(path, mode) {
- path = PATH.normalize(path);
- if (path[path.length - 1] === "/") path = path.substr(0, path.length - 1);
- FS.mkdir(path, mode, 0);
- return 0;
- }),
- doMknod: (function(path, mode, dev) {
- switch (mode & 61440) {
- case 32768:
- case 8192:
- case 24576:
- case 4096:
- case 49152:
- break;
- default:
- return -ERRNO_CODES.EINVAL;
- }
- FS.mknod(path, mode, dev);
- return 0;
- }),
- doReadlink: (function(path, buf, bufsize) {
- if (bufsize <= 0) return -ERRNO_CODES.EINVAL;
- var ret = FS.readlink(path);
- var len = Math.min(bufsize, lengthBytesUTF8(ret));
- var endChar = HEAP8[buf + len];
- stringToUTF8(ret, buf, bufsize + 1);
- HEAP8[buf + len] = endChar;
- return len;
- }),
- doAccess: (function(path, amode) {
- if (amode & ~7) {
- return -ERRNO_CODES.EINVAL;
- }
- var node;
- var lookup = FS.lookupPath(path, {
- follow: true
- });
- node = lookup.node;
- var perms = "";
- if (amode & 4) perms += "r";
- if (amode & 2) perms += "w";
- if (amode & 1) perms += "x";
- if (perms && FS.nodePermissions(node, perms)) {
- return -ERRNO_CODES.EACCES;
- }
- return 0;
- }),
- doDup: (function(path, flags, suggestFD) {
- var suggest = FS.getStream(suggestFD);
- if (suggest) FS.close(suggest);
- return FS.open(path, flags, 0, suggestFD, suggestFD).fd;
- }),
- doReadv: (function(stream, iov, iovcnt, offset) {
- var ret = 0;
- for (var i = 0; i < iovcnt; i++) {
- var ptr = HEAP32[iov + i * 8 >> 2];
- var len = HEAP32[iov + (i * 8 + 4) >> 2];
- var curr = FS.read(stream, HEAP8, ptr, len, offset);
- if (curr < 0) return -1;
- ret += curr;
- if (curr < len) break;
- }
- return ret;
- }),
- doWritev: (function(stream, iov, iovcnt, offset) {
- var ret = 0;
- for (var i = 0; i < iovcnt; i++) {
- var ptr = HEAP32[iov + i * 8 >> 2];
- var len = HEAP32[iov + (i * 8 + 4) >> 2];
- var curr = FS.write(stream, HEAP8, ptr, len, offset);
- if (curr < 0) return -1;
- ret += curr;
- }
- return ret;
- }),
- varargs: 0,
- get: (function(varargs) {
- SYSCALLS.varargs += 4;
- var ret = HEAP32[SYSCALLS.varargs - 4 >> 2];
- return ret;
- }),
- getStr: (function() {
- var ret = Pointer_stringify(SYSCALLS.get());
- return ret;
- }),
- getStreamFromFD: (function() {
- var stream = FS.getStream(SYSCALLS.get());
- if (!stream) throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- return stream;
- }),
- getSocketFromFD: (function() {
- var socket = SOCKFS.getSocket(SYSCALLS.get());
- if (!socket) throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- return socket;
- }),
- getSocketAddress: (function(allowNull) {
- var addrp = SYSCALLS.get(), addrlen = SYSCALLS.get();
- if (allowNull && addrp === 0) return null;
- var info = __read_sockaddr(addrp, addrlen);
- if (info.errno) throw new FS.ErrnoError(info.errno);
- info.addr = DNS.lookup_addr(info.addr) || info.addr;
- return info;
- }),
- get64: (function() {
- var low = SYSCALLS.get(), high = SYSCALLS.get();
- if (low >= 0) assert(high === 0); else assert(high === -1);
- return low;
- }),
- getZero: (function() {
- assert(SYSCALLS.get() === 0);
- })
-};
-function ___syscall140(which, varargs) {
- SYSCALLS.varargs = varargs;
- try {
- var stream = SYSCALLS.getStreamFromFD(), offset_high = SYSCALLS.get(), offset_low = SYSCALLS.get(), result = SYSCALLS.get(), whence = SYSCALLS.get();
- var offset = offset_low;
- FS.llseek(stream, offset, whence);
- HEAP32[result >> 2] = stream.position;
- if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null;
- return 0;
- } catch (e) {
- if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) abort(e);
- return -e.errno;
- }
-}
-function ___syscall145(which, varargs) {
- SYSCALLS.varargs = varargs;
- try {
- var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get();
- return SYSCALLS.doReadv(stream, iov, iovcnt);
- } catch (e) {
- if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) abort(e);
- return -e.errno;
- }
-}
-function ___syscall146(which, varargs) {
- SYSCALLS.varargs = varargs;
- try {
- var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get();
- return SYSCALLS.doWritev(stream, iov, iovcnt);
- } catch (e) {
- if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) abort(e);
- return -e.errno;
- }
-}
-function ___syscall54(which, varargs) {
- SYSCALLS.varargs = varargs;
- try {
- var stream = SYSCALLS.getStreamFromFD(), op = SYSCALLS.get();
- switch (op) {
- case 21509:
- case 21505:
- {
- if (!stream.tty) return -ERRNO_CODES.ENOTTY;
- return 0;
- }
- case 21510:
- case 21511:
- case 21512:
- case 21506:
- case 21507:
- case 21508:
- {
- if (!stream.tty) return -ERRNO_CODES.ENOTTY;
- return 0;
- }
- case 21519:
- {
- if (!stream.tty) return -ERRNO_CODES.ENOTTY;
- var argp = SYSCALLS.get();
- HEAP32[argp >> 2] = 0;
- return 0;
- }
- case 21520:
- {
- if (!stream.tty) return -ERRNO_CODES.ENOTTY;
- return -ERRNO_CODES.EINVAL;
- }
- case 21531:
- {
- var argp = SYSCALLS.get();
- return FS.ioctl(stream, op, argp);
- }
- case 21523:
- {
- if (!stream.tty) return -ERRNO_CODES.ENOTTY;
- return 0;
- }
- case 21524:
- {
- if (!stream.tty) return -ERRNO_CODES.ENOTTY;
- return 0;
- }
- default:
- abort("bad ioctl syscall " + op);
- }
- } catch (e) {
- if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) abort(e);
- return -e.errno;
- }
-}
-function ___syscall6(which, varargs) {
- SYSCALLS.varargs = varargs;
- try {
- var stream = SYSCALLS.getStreamFromFD();
- FS.close(stream);
- return 0;
- } catch (e) {
- if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) abort(e);
- return -e.errno;
- }
-}
-function ___syscall91(which, varargs) {
- SYSCALLS.varargs = varargs;
- try {
- var addr = SYSCALLS.get(), len = SYSCALLS.get();
- var info = SYSCALLS.mappings[addr];
- if (!info) return 0;
- if (len === info.len) {
- var stream = FS.getStream(info.fd);
- SYSCALLS.doMsync(addr, stream, len, info.flags);
- FS.munmap(stream);
- SYSCALLS.mappings[addr] = null;
- if (info.allocated) {
- _free(info.malloc);
- }
- }
- return 0;
- } catch (e) {
- if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) abort(e);
- return -e.errno;
- }
-}
-function ___unlock() {}
-function _abort() {
- Module["abort"]();
-}
-var _environ = STATICTOP;
-STATICTOP += 16;
-function ___buildEnvironment(env) {
- var MAX_ENV_VALUES = 64;
- var TOTAL_ENV_SIZE = 1024;
- var poolPtr;
- var envPtr;
- if (!___buildEnvironment.called) {
- ___buildEnvironment.called = true;
- ENV["USER"] = ENV["LOGNAME"] = "web_user";
- ENV["PATH"] = "/";
- ENV["PWD"] = "/";
- ENV["HOME"] = "/home/web_user";
- ENV["LANG"] = "C.UTF-8";
- ENV["_"] = Module["thisProgram"];
- poolPtr = staticAlloc(TOTAL_ENV_SIZE);
- envPtr = staticAlloc(MAX_ENV_VALUES * 4);
- HEAP32[envPtr >> 2] = poolPtr;
- HEAP32[_environ >> 2] = envPtr;
- } else {
- envPtr = HEAP32[_environ >> 2];
- poolPtr = HEAP32[envPtr >> 2];
- }
- var strings = [];
- var totalSize = 0;
- for (var key in env) {
- if (typeof env[key] === "string") {
- var line = key + "=" + env[key];
- strings.push(line);
- totalSize += line.length;
- }
- }
- if (totalSize > TOTAL_ENV_SIZE) {
- throw new Error("Environment size exceeded TOTAL_ENV_SIZE!");
- }
- var ptrSize = 4;
- for (var i = 0; i < strings.length; i++) {
- var line = strings[i];
- writeAsciiToMemory(line, poolPtr);
- HEAP32[envPtr + i * ptrSize >> 2] = poolPtr;
- poolPtr += line.length + 1;
- }
- HEAP32[envPtr + strings.length * ptrSize >> 2] = 0;
-}
-var ENV = {};
-function _getenv(name) {
- if (name === 0) return 0;
- name = Pointer_stringify(name);
- if (!ENV.hasOwnProperty(name)) return 0;
- if (_getenv.ret) _free(_getenv.ret);
- _getenv.ret = allocateUTF8(ENV[name]);
- return _getenv.ret;
-}
-function _gettimeofday(ptr) {
- var now = Date.now();
- HEAP32[ptr >> 2] = now / 1e3 | 0;
- HEAP32[ptr + 4 >> 2] = now % 1e3 * 1e3 | 0;
- return 0;
-}
-function _emscripten_memcpy_big(dest, src, num) {
- HEAPU8.set(HEAPU8.subarray(src, src + num), dest);
- return dest;
-}
-function _pthread_cond_wait() {
- return 0;
-}
-var PTHREAD_SPECIFIC = {};
-function _pthread_getspecific(key) {
- return PTHREAD_SPECIFIC[key] || 0;
-}
-var PTHREAD_SPECIFIC_NEXT_KEY = 1;
-function _pthread_key_create(key, destructor) {
- if (key == 0) {
- return ERRNO_CODES.EINVAL;
- }
- HEAP32[key >> 2] = PTHREAD_SPECIFIC_NEXT_KEY;
- PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0;
- PTHREAD_SPECIFIC_NEXT_KEY++;
- return 0;
-}
-function _pthread_once(ptr, func) {
- if (!_pthread_once.seen) _pthread_once.seen = {};
- if (ptr in _pthread_once.seen) return;
- Module["dynCall_v"](func);
- _pthread_once.seen[ptr] = 1;
-}
-function _pthread_setspecific(key, value) {
- if (!(key in PTHREAD_SPECIFIC)) {
- return ERRNO_CODES.EINVAL;
- }
- PTHREAD_SPECIFIC[key] = value;
- return 0;
-}
-function __isLeapYear(year) {
- return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
-}
-function __arraySum(array, index) {
- var sum = 0;
- for (var i = 0; i <= index; sum += array[i++]) ;
- return sum;
-}
-var __MONTH_DAYS_LEAP = [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
-var __MONTH_DAYS_REGULAR = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
-function __addDays(date, days) {
- var newDate = new Date(date.getTime());
- while (days > 0) {
- var leap = __isLeapYear(newDate.getFullYear());
- var currentMonth = newDate.getMonth();
- var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
- if (days > daysInCurrentMonth - newDate.getDate()) {
- days -= daysInCurrentMonth - newDate.getDate() + 1;
- newDate.setDate(1);
- if (currentMonth < 11) {
- newDate.setMonth(currentMonth + 1);
- } else {
- newDate.setMonth(0);
- newDate.setFullYear(newDate.getFullYear() + 1);
- }
- } else {
- newDate.setDate(newDate.getDate() + days);
- return newDate;
- }
- }
- return newDate;
-}
-function _strftime(s, maxsize, format, tm) {
- var tm_zone = HEAP32[tm + 40 >> 2];
- var date = {
- tm_sec: HEAP32[tm >> 2],
- tm_min: HEAP32[tm + 4 >> 2],
- tm_hour: HEAP32[tm + 8 >> 2],
- tm_mday: HEAP32[tm + 12 >> 2],
- tm_mon: HEAP32[tm + 16 >> 2],
- tm_year: HEAP32[tm + 20 >> 2],
- tm_wday: HEAP32[tm + 24 >> 2],
- tm_yday: HEAP32[tm + 28 >> 2],
- tm_isdst: HEAP32[tm + 32 >> 2],
- tm_gmtoff: HEAP32[tm + 36 >> 2],
- tm_zone: tm_zone ? Pointer_stringify(tm_zone) : ""
- };
- var pattern = Pointer_stringify(format);
- var EXPANSION_RULES_1 = {
- "%c": "%a %b %d %H:%M:%S %Y",
- "%D": "%m/%d/%y",
- "%F": "%Y-%m-%d",
- "%h": "%b",
- "%r": "%I:%M:%S %p",
- "%R": "%H:%M",
- "%T": "%H:%M:%S",
- "%x": "%m/%d/%y",
- "%X": "%H:%M:%S"
- };
- for (var rule in EXPANSION_RULES_1) {
- pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_1[rule]);
- }
- var WEEKDAYS = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
- var MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
- function leadingSomething(value, digits, character) {
- var str = typeof value === "number" ? value.toString() : value || "";
- while (str.length < digits) {
- str = character[0] + str;
- }
- return str;
- }
- function leadingNulls(value, digits) {
- return leadingSomething(value, digits, "0");
- }
- function compareByDay(date1, date2) {
- function sgn(value) {
- return value < 0 ? -1 : value > 0 ? 1 : 0;
- }
- var compare;
- if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {
- if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {
- compare = sgn(date1.getDate() - date2.getDate());
- }
- }
- return compare;
- }
- function getFirstWeekStartDate(janFourth) {
- switch (janFourth.getDay()) {
- case 0:
- return new Date(janFourth.getFullYear() - 1, 11, 29);
- case 1:
- return janFourth;
- case 2:
- return new Date(janFourth.getFullYear(), 0, 3);
- case 3:
- return new Date(janFourth.getFullYear(), 0, 2);
- case 4:
- return new Date(janFourth.getFullYear(), 0, 1);
- case 5:
- return new Date(janFourth.getFullYear() - 1, 11, 31);
- case 6:
- return new Date(janFourth.getFullYear() - 1, 11, 30);
- }
- }
- function getWeekBasedYear(date) {
- var thisDate = __addDays(new Date(date.tm_year + 1900, 0, 1), date.tm_yday);
- var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4);
- var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4);
- var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
- var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
- if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {
- if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {
- return thisDate.getFullYear() + 1;
- } else {
- return thisDate.getFullYear();
- }
- } else {
- return thisDate.getFullYear() - 1;
- }
- }
- var EXPANSION_RULES_2 = {
- "%a": (function(date) {
- return WEEKDAYS[date.tm_wday].substring(0, 3);
- }),
- "%A": (function(date) {
- return WEEKDAYS[date.tm_wday];
- }),
- "%b": (function(date) {
- return MONTHS[date.tm_mon].substring(0, 3);
- }),
- "%B": (function(date) {
- return MONTHS[date.tm_mon];
- }),
- "%C": (function(date) {
- var year = date.tm_year + 1900;
- return leadingNulls(year / 100 | 0, 2);
- }),
- "%d": (function(date) {
- return leadingNulls(date.tm_mday, 2);
- }),
- "%e": (function(date) {
- return leadingSomething(date.tm_mday, 2, " ");
- }),
- "%g": (function(date) {
- return getWeekBasedYear(date).toString().substring(2);
- }),
- "%G": (function(date) {
- return getWeekBasedYear(date);
- }),
- "%H": (function(date) {
- return leadingNulls(date.tm_hour, 2);
- }),
- "%I": (function(date) {
- var twelveHour = date.tm_hour;
- if (twelveHour == 0) twelveHour = 12; else if (twelveHour > 12) twelveHour -= 12;
- return leadingNulls(twelveHour, 2);
- }),
- "%j": (function(date) {
- return leadingNulls(date.tm_mday + __arraySum(__isLeapYear(date.tm_year + 1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon - 1), 3);
- }),
- "%m": (function(date) {
- return leadingNulls(date.tm_mon + 1, 2);
- }),
- "%M": (function(date) {
- return leadingNulls(date.tm_min, 2);
- }),
- "%n": (function() {
- return "\n";
- }),
- "%p": (function(date) {
- if (date.tm_hour >= 0 && date.tm_hour < 12) {
- return "AM";
- } else {
- return "PM";
- }
- }),
- "%S": (function(date) {
- return leadingNulls(date.tm_sec, 2);
- }),
- "%t": (function() {
- return "\t";
- }),
- "%u": (function(date) {
- var day = new Date(date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, 0, 0, 0, 0);
- return day.getDay() || 7;
- }),
- "%U": (function(date) {
- var janFirst = new Date(date.tm_year + 1900, 0, 1);
- var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7 - janFirst.getDay());
- var endDate = new Date(date.tm_year + 1900, date.tm_mon, date.tm_mday);
- if (compareByDay(firstSunday, endDate) < 0) {
- var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth() - 1) - 31;
- var firstSundayUntilEndJanuary = 31 - firstSunday.getDate();
- var days = firstSundayUntilEndJanuary + februaryFirstUntilEndMonth + endDate.getDate();
- return leadingNulls(Math.ceil(days / 7), 2);
- }
- return compareByDay(firstSunday, janFirst) === 0 ? "01" : "00";
- }),
- "%V": (function(date) {
- var janFourthThisYear = new Date(date.tm_year + 1900, 0, 4);
- var janFourthNextYear = new Date(date.tm_year + 1901, 0, 4);
- var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
- var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
- var endDate = __addDays(new Date(date.tm_year + 1900, 0, 1), date.tm_yday);
- if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
- return "53";
- }
- if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
- return "01";
- }
- var daysDifference;
- if (firstWeekStartThisYear.getFullYear() < date.tm_year + 1900) {
- daysDifference = date.tm_yday + 32 - firstWeekStartThisYear.getDate();
- } else {
- daysDifference = date.tm_yday + 1 - firstWeekStartThisYear.getDate();
- }
- return leadingNulls(Math.ceil(daysDifference / 7), 2);
- }),
- "%w": (function(date) {
- var day = new Date(date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, 0, 0, 0, 0);
- return day.getDay();
- }),
- "%W": (function(date) {
- var janFirst = new Date(date.tm_year, 0, 1);
- var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7 - janFirst.getDay() + 1);
- var endDate = new Date(date.tm_year + 1900, date.tm_mon, date.tm_mday);
- if (compareByDay(firstMonday, endDate) < 0) {
- var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth() - 1) - 31;
- var firstMondayUntilEndJanuary = 31 - firstMonday.getDate();
- var days = firstMondayUntilEndJanuary + februaryFirstUntilEndMonth + endDate.getDate();
- return leadingNulls(Math.ceil(days / 7), 2);
- }
- return compareByDay(firstMonday, janFirst) === 0 ? "01" : "00";
- }),
- "%y": (function(date) {
- return (date.tm_year + 1900).toString().substring(2);
- }),
- "%Y": (function(date) {
- return date.tm_year + 1900;
- }),
- "%z": (function(date) {
- var off = date.tm_gmtoff;
- var ahead = off >= 0;
- off = Math.abs(off) / 60;
- off = off / 60 * 100 + off % 60;
- return (ahead ? "+" : "-") + String("0000" + off).slice(-4);
- }),
- "%Z": (function(date) {
- return date.tm_zone;
- }),
- "%%": (function() {
- return "%";
- })
- };
- for (var rule in EXPANSION_RULES_2) {
- if (pattern.indexOf(rule) >= 0) {
- pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_2[rule](date));
- }
- }
- var bytes = intArrayFromString(pattern, false);
- if (bytes.length > maxsize) {
- return 0;
- }
- writeArrayToMemory(bytes, s);
- return bytes.length - 1;
-}
-function _strftime_l(s, maxsize, format, tm) {
- return _strftime(s, maxsize, format, tm);
-}
-FS.staticInit();
-__ATINIT__.unshift((function() {
- if (!Module["noFSInit"] && !FS.init.initialized) FS.init();
-}));
-__ATMAIN__.push((function() {
- FS.ignorePermissions = false;
-}));
-__ATEXIT__.push((function() {
- FS.quit();
-}));
-__ATINIT__.unshift((function() {
- TTY.init();
-}));
-__ATEXIT__.push((function() {
- TTY.shutdown();
-}));
-if (ENVIRONMENT_IS_NODE) {
- var fs = require("fs");
- var NODEJS_PATH = require("path");
- NODEFS.staticInit();
-}
-___buildEnvironment(ENV);
-DYNAMICTOP_PTR = staticAlloc(4);
-STACK_BASE = STACKTOP = alignMemory(STATICTOP);
-STACK_MAX = STACK_BASE + TOTAL_STACK;
-DYNAMIC_BASE = alignMemory(STACK_MAX);
-HEAP32[DYNAMICTOP_PTR >> 2] = DYNAMIC_BASE;
-staticSealed = true;
-var ASSERTIONS = false;
-function intArrayFromString(stringy, dontAddNull, length) {
- var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1;
- var u8array = new Array(len);
- var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
- if (dontAddNull) u8array.length = numBytesWritten;
- return u8array;
-}
-Module["wasmTableSize"] = 481;
-Module["wasmMaxTableSize"] = 481;
-function invoke_ii(index, a1) {
- try {
- return Module["dynCall_ii"](index, a1);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iii(index, a1, a2) {
- try {
- return Module["dynCall_iii"](index, a1, a2);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiii(index, a1, a2, a3) {
- try {
- return Module["dynCall_iiii"](index, a1, a2, a3);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiii(index, a1, a2, a3, a4) {
- try {
- return Module["dynCall_iiiii"](index, a1, a2, a3, a4);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiid(index, a1, a2, a3, a4, a5) {
- try {
- return Module["dynCall_iiiiid"](index, a1, a2, a3, a4, a5);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiii(index, a1, a2, a3, a4, a5) {
- try {
- return Module["dynCall_iiiiii"](index, a1, a2, a3, a4, a5);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiiid(index, a1, a2, a3, a4, a5, a6) {
- try {
- return Module["dynCall_iiiiiid"](index, a1, a2, a3, a4, a5, a6);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiiii(index, a1, a2, a3, a4, a5, a6) {
- try {
- return Module["dynCall_iiiiiii"](index, a1, a2, a3, a4, a5, a6);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiiiii(index, a1, a2, a3, a4, a5, a6, a7) {
- try {
- return Module["dynCall_iiiiiiii"](index, a1, a2, a3, a4, a5, a6, a7);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8) {
- try {
- return Module["dynCall_iiiiiiiii"](index, a1, a2, a3, a4, a5, a6, a7, a8);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_iiiiij(index, a1, a2, a3, a4, a5, a6) {
- try {
- return Module["dynCall_iiiiij"](index, a1, a2, a3, a4, a5, a6);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_v(index) {
- try {
- Module["dynCall_v"](index);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_vi(index, a1) {
- try {
- Module["dynCall_vi"](index, a1);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_vii(index, a1, a2) {
- try {
- Module["dynCall_vii"](index, a1, a2);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_viii(index, a1, a2, a3) {
- try {
- Module["dynCall_viii"](index, a1, a2, a3);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_viiii(index, a1, a2, a3, a4) {
- try {
- Module["dynCall_viiii"](index, a1, a2, a3, a4);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_viiiii(index, a1, a2, a3, a4, a5) {
- try {
- Module["dynCall_viiiii"](index, a1, a2, a3, a4, a5);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_viiiiii(index, a1, a2, a3, a4, a5, a6) {
- try {
- Module["dynCall_viiiiii"](index, a1, a2, a3, a4, a5, a6);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-function invoke_viijii(index, a1, a2, a3, a4, a5, a6) {
- try {
- Module["dynCall_viijii"](index, a1, a2, a3, a4, a5, a6);
- } catch (e) {
- if (typeof e !== "number" && e !== "longjmp") throw e;
- Module["setThrew"](1, 0);
- }
-}
-Module.asmGlobalArg = {};
-Module.asmLibraryArg = {
- "abort": abort,
- "assert": assert,
- "enlargeMemory": enlargeMemory,
- "getTotalMemory": getTotalMemory,
- "abortOnCannotGrowMemory": abortOnCannotGrowMemory,
- "invoke_ii": invoke_ii,
- "invoke_iii": invoke_iii,
- "invoke_iiii": invoke_iiii,
- "invoke_iiiii": invoke_iiiii,
- "invoke_iiiiid": invoke_iiiiid,
- "invoke_iiiiii": invoke_iiiiii,
- "invoke_iiiiiid": invoke_iiiiiid,
- "invoke_iiiiiii": invoke_iiiiiii,
- "invoke_iiiiiiii": invoke_iiiiiiii,
- "invoke_iiiiiiiii": invoke_iiiiiiiii,
- "invoke_iiiiij": invoke_iiiiij,
- "invoke_v": invoke_v,
- "invoke_vi": invoke_vi,
- "invoke_vii": invoke_vii,
- "invoke_viii": invoke_viii,
- "invoke_viiii": invoke_viiii,
- "invoke_viiiii": invoke_viiiii,
- "invoke_viiiiii": invoke_viiiiii,
- "invoke_viijii": invoke_viijii,
- "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv,
- "___buildEnvironment": ___buildEnvironment,
- "___cxa_allocate_exception": ___cxa_allocate_exception,
- "___cxa_begin_catch": ___cxa_begin_catch,
- "___cxa_find_matching_catch": ___cxa_find_matching_catch,
- "___cxa_throw": ___cxa_throw,
- "___gxx_personality_v0": ___gxx_personality_v0,
- "___lock": ___lock,
- "___map_file": ___map_file,
- "___resumeException": ___resumeException,
- "___setErrNo": ___setErrNo,
- "___syscall140": ___syscall140,
- "___syscall145": ___syscall145,
- "___syscall146": ___syscall146,
- "___syscall54": ___syscall54,
- "___syscall6": ___syscall6,
- "___syscall91": ___syscall91,
- "___unlock": ___unlock,
- "__addDays": __addDays,
- "__arraySum": __arraySum,
- "__isLeapYear": __isLeapYear,
- "_abort": _abort,
- "_emscripten_memcpy_big": _emscripten_memcpy_big,
- "_getenv": _getenv,
- "_gettimeofday": _gettimeofday,
- "_pthread_cond_wait": _pthread_cond_wait,
- "_pthread_getspecific": _pthread_getspecific,
- "_pthread_key_create": _pthread_key_create,
- "_pthread_once": _pthread_once,
- "_pthread_setspecific": _pthread_setspecific,
- "_strftime": _strftime,
- "_strftime_l": _strftime_l,
- "DYNAMICTOP_PTR": DYNAMICTOP_PTR,
- "tempDoublePtr": tempDoublePtr,
- "ABORT": ABORT,
- "STACKTOP": STACKTOP,
- "STACK_MAX": STACK_MAX
-};
-var asm = Module["asm"](Module.asmGlobalArg, Module.asmLibraryArg, buffer);
-Module["asm"] = asm;
-var __GLOBAL__I_000101 = Module["__GLOBAL__I_000101"] = (function() {
- return Module["asm"]["__GLOBAL__I_000101"].apply(null, arguments);
-});
-var __GLOBAL__sub_I_iostream_cpp = Module["__GLOBAL__sub_I_iostream_cpp"] = (function() {
- return Module["asm"]["__GLOBAL__sub_I_iostream_cpp"].apply(null, arguments);
-});
-var ___cxa_can_catch = Module["___cxa_can_catch"] = (function() {
- return Module["asm"]["___cxa_can_catch"].apply(null, arguments);
-});
-var ___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = (function() {
- return Module["asm"]["___cxa_is_pointer_type"].apply(null, arguments);
-});
-var ___errno_location = Module["___errno_location"] = (function() {
- return Module["asm"]["___errno_location"].apply(null, arguments);
-});
-var _free = Module["_free"] = (function() {
- return Module["asm"]["_free"].apply(null, arguments);
-});
-var _llvm_bswap_i32 = Module["_llvm_bswap_i32"] = (function() {
- return Module["asm"]["_llvm_bswap_i32"].apply(null, arguments);
-});
-var _main = Module["_main"] = (function() {
- let start = benchmarkTime();
- let ret = Module["asm"]["_main"].apply(null, arguments);
- reportRunTime(benchmarkTime() - start);
- return ret;
-});
-var _malloc = Module["_malloc"] = (function() {
- return Module["asm"]["_malloc"].apply(null, arguments);
-});
-var _memcpy = Module["_memcpy"] = (function() {
- return Module["asm"]["_memcpy"].apply(null, arguments);
-});
-var _memmove = Module["_memmove"] = (function() {
- return Module["asm"]["_memmove"].apply(null, arguments);
-});
-var _memset = Module["_memset"] = (function() {
- return Module["asm"]["_memset"].apply(null, arguments);
-});
-var _pthread_cond_broadcast = Module["_pthread_cond_broadcast"] = (function() {
- return Module["asm"]["_pthread_cond_broadcast"].apply(null, arguments);
-});
-var _pthread_mutex_lock = Module["_pthread_mutex_lock"] = (function() {
- return Module["asm"]["_pthread_mutex_lock"].apply(null, arguments);
-});
-var _pthread_mutex_unlock = Module["_pthread_mutex_unlock"] = (function() {
- return Module["asm"]["_pthread_mutex_unlock"].apply(null, arguments);
-});
-var _sbrk = Module["_sbrk"] = (function() {
- return Module["asm"]["_sbrk"].apply(null, arguments);
-});
-var establishStackSpace = Module["establishStackSpace"] = (function() {
- return Module["asm"]["establishStackSpace"].apply(null, arguments);
-});
-var getTempRet0 = Module["getTempRet0"] = (function() {
- return Module["asm"]["getTempRet0"].apply(null, arguments);
-});
-var runPostSets = Module["runPostSets"] = (function() {
- return Module["asm"]["runPostSets"].apply(null, arguments);
-});
-var setTempRet0 = Module["setTempRet0"] = (function() {
- return Module["asm"]["setTempRet0"].apply(null, arguments);
-});
-var setThrew = Module["setThrew"] = (function() {
- return Module["asm"]["setThrew"].apply(null, arguments);
-});
-var stackAlloc = Module["stackAlloc"] = (function() {
- return Module["asm"]["stackAlloc"].apply(null, arguments);
-});
-var stackRestore = Module["stackRestore"] = (function() {
- return Module["asm"]["stackRestore"].apply(null, arguments);
-});
-var stackSave = Module["stackSave"] = (function() {
- return Module["asm"]["stackSave"].apply(null, arguments);
-});
-var dynCall_ii = Module["dynCall_ii"] = (function() {
- return Module["asm"]["dynCall_ii"].apply(null, arguments);
-});
-var dynCall_iii = Module["dynCall_iii"] = (function() {
- return Module["asm"]["dynCall_iii"].apply(null, arguments);
-});
-var dynCall_iiii = Module["dynCall_iiii"] = (function() {
- return Module["asm"]["dynCall_iiii"].apply(null, arguments);
-});
-var dynCall_iiiii = Module["dynCall_iiiii"] = (function() {
- return Module["asm"]["dynCall_iiiii"].apply(null, arguments);
-});
-var dynCall_iiiiid = Module["dynCall_iiiiid"] = (function() {
- return Module["asm"]["dynCall_iiiiid"].apply(null, arguments);
-});
-var dynCall_iiiiii = Module["dynCall_iiiiii"] = (function() {
- return Module["asm"]["dynCall_iiiiii"].apply(null, arguments);
-});
-var dynCall_iiiiiid = Module["dynCall_iiiiiid"] = (function() {
- return Module["asm"]["dynCall_iiiiiid"].apply(null, arguments);
-});
-var dynCall_iiiiiii = Module["dynCall_iiiiiii"] = (function() {
- return Module["asm"]["dynCall_iiiiiii"].apply(null, arguments);
-});
-var dynCall_iiiiiiii = Module["dynCall_iiiiiiii"] = (function() {
- return Module["asm"]["dynCall_iiiiiiii"].apply(null, arguments);
-});
-var dynCall_iiiiiiiii = Module["dynCall_iiiiiiiii"] = (function() {
- return Module["asm"]["dynCall_iiiiiiiii"].apply(null, arguments);
-});
-var dynCall_iiiiij = Module["dynCall_iiiiij"] = (function() {
- return Module["asm"]["dynCall_iiiiij"].apply(null, arguments);
-});
-var dynCall_v = Module["dynCall_v"] = (function() {
- return Module["asm"]["dynCall_v"].apply(null, arguments);
-});
-var dynCall_vi = Module["dynCall_vi"] = (function() {
- return Module["asm"]["dynCall_vi"].apply(null, arguments);
-});
-var dynCall_vii = Module["dynCall_vii"] = (function() {
- return Module["asm"]["dynCall_vii"].apply(null, arguments);
-});
-var dynCall_viii = Module["dynCall_viii"] = (function() {
- return Module["asm"]["dynCall_viii"].apply(null, arguments);
-});
-var dynCall_viiii = Module["dynCall_viiii"] = (function() {
- return Module["asm"]["dynCall_viiii"].apply(null, arguments);
-});
-var dynCall_viiiii = Module["dynCall_viiiii"] = (function() {
- return Module["asm"]["dynCall_viiiii"].apply(null, arguments);
-});
-var dynCall_viiiiii = Module["dynCall_viiiiii"] = (function() {
- return Module["asm"]["dynCall_viiiiii"].apply(null, arguments);
-});
-var dynCall_viijii = Module["dynCall_viijii"] = (function() {
- return Module["asm"]["dynCall_viijii"].apply(null, arguments);
-});
-Module["asm"] = asm;
-function ExitStatus(status) {
- this.name = "ExitStatus";
- this.message = "Program terminated with exit(" + status + ")";
- this.status = status;
-}
-ExitStatus.prototype = new Error;
-ExitStatus.prototype.constructor = ExitStatus;
-var initialStackTop;
-var calledMain = false;
-dependenciesFulfilled = function runCaller() {
- if (!Module["calledRun"]) run();
- if (!Module["calledRun"]) dependenciesFulfilled = runCaller;
-};
-Module["callMain"] = function callMain(args) {
- args = args || [];
- ensureInitRuntime();
- var argc = args.length + 1;
- var argv = stackAlloc((argc + 1) * 4);
- HEAP32[argv >> 2] = allocateUTF8OnStack(Module["thisProgram"]);
- for (var i = 1; i < argc; i++) {
- HEAP32[(argv >> 2) + i] = allocateUTF8OnStack(args[i - 1]);
- }
- HEAP32[(argv >> 2) + argc] = 0;
- try {
- var ret = Module["_main"](argc, argv, 0);
- exit(ret, true);
- } catch (e) {
- if (e instanceof ExitStatus) {
- return;
- } else if (e == "SimulateInfiniteLoop") {
- Module["noExitRuntime"] = true;
- return;
- } else {
- var toLog = e;
- if (e && typeof e === "object" && e.stack) {
- toLog = [ e, e.stack ];
- }
- Module.printErr("exception thrown: " + toLog);
- Module["quit"](1, e);
- }
- } finally {
- calledMain = true;
- }
-};
-function run(args) {
- args = args || Module["arguments"];
- if (runDependencies > 0) {
- return;
- }
- preRun();
- if (runDependencies > 0) return;
- if (Module["calledRun"]) return;
- function doRun() {
- if (Module["calledRun"]) return;
- Module["calledRun"] = true;
- if (ABORT) return;
- ensureInitRuntime();
- preMain();
- if (Module["onRuntimeInitialized"]) Module["onRuntimeInitialized"]();
- if (Module["_main"] && shouldRunNow) Module["callMain"](args);
- postRun();
- }
- if (Module["setStatus"]) {
- Module["setStatus"]("Running...");
- setTimeout((function() {
- setTimeout((function() {
- Module["setStatus"]("");
- }), 1);
- doRun();
- }), 1);
- } else {
- doRun();
- }
-}
-Module["run"] = run;
-function exit(status, implicit) {
- if (implicit && Module["noExitRuntime"] && status === 0) {
- return;
- }
- if (Module["noExitRuntime"]) {} else {
- ABORT = true;
- EXITSTATUS = status;
- STACKTOP = initialStackTop;
- exitRuntime();
- if (Module["onExit"]) Module["onExit"](status);
- }
- if (ENVIRONMENT_IS_NODE) {
- process["exit"](status);
- }
- Module["quit"](status, new ExitStatus(status));
-}
-Module["exit"] = exit;
-function abort(what) {
- if (Module["onAbort"]) {
- Module["onAbort"](what);
- }
- if (what !== undefined) {
- Module.print(what);
- Module.printErr(what);
- what = JSON.stringify(what);
- } else {
- what = "";
- }
- ABORT = true;
- EXITSTATUS = 1;
- throw "abort(" + what + "). Build with -s ASSERTIONS=1 for more info.";
-}
-Module["abort"] = abort;
-if (Module["preInit"]) {
- if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ];
- while (Module["preInit"].length > 0) {
- Module["preInit"].pop()();
- }
-}
-var shouldRunNow = true;
-if (Module["noInitialRun"]) {
- shouldRunNow = false;
-}
-Module["noExitRuntime"] = true;
-run();
-}
diff --git a/wasm/gcc-loops.wasm b/wasm/gcc-loops.wasm
deleted file mode 100644
index cb5f902..0000000
--- a/wasm/gcc-loops.wasm
+++ /dev/null
Binary files differ
diff --git a/wasm/gcc-loops/benchmark.js b/wasm/gcc-loops/benchmark.js
new file mode 100644
index 0000000..0297acf
--- /dev/null
+++ b/wasm/gcc-loops/benchmark.js
@@ -0,0 +1,12 @@
+// Copyright 2025 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class Benchmark {
+ async runIteration() {
+ if (!Module._main)
+ await setupModule(Module);
+
+ Module._main();
+ }
+};
diff --git a/wasm/gcc-loops/build.log b/wasm/gcc-loops/build.log
new file mode 100644
index 0000000..0659792
--- /dev/null
+++ b/wasm/gcc-loops/build.log
@@ -0,0 +1,5 @@
+Built on 2025-01-16T14:50:15Z
+Toolchain versions
+emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.73 (ac676d5e437525d15df5fd46bc2c208ec6d376a3)
+Building...
+Building done
diff --git a/wasm/gcc-loops/build.sh b/wasm/gcc-loops/build.sh
new file mode 100755
index 0000000..3e0bf79
--- /dev/null
+++ b/wasm/gcc-loops/build.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -euo pipefail
+
+touch build.log
+BUILD_LOG="$(realpath build.log)"
+echo "Built on $(date -u '+%Y-%m-%dT%H:%M:%SZ')" | tee "$BUILD_LOG"
+
+echo "Toolchain versions" | tee -a "$BUILD_LOG"
+emcc --version | head -n1 | tee -a "$BUILD_LOG"
+
+echo "Building..." | tee -a "$BUILD_LOG"
+mkdir -p build
+emcc -o build/gcc-loops.js \
+ -s WASM=1 -O2 \
+ -g1 --emit-symbol-map \
+ -s MODULARIZE=1 -s EXPORT_NAME=setupModule \
+ -DSMALL_PROBLEM_SIZE=1 \
+ gcc-loops.cpp | tee -a "$BUILD_LOG"
+
+echo "Building done" | tee -a "$BUILD_LOG"
diff --git a/wasm/gcc-loops/build/gcc-loops.js b/wasm/gcc-loops/build/gcc-loops.js
new file mode 100644
index 0000000..bf35d7d
--- /dev/null
+++ b/wasm/gcc-loops/build/gcc-loops.js
@@ -0,0 +1,3553 @@
+
+var setupModule = (() => {
+ var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
+ if (typeof __filename != 'undefined') _scriptName = _scriptName || __filename;
+ return (
+function(moduleArg = {}) {
+ var moduleRtn;
+
+// include: shell.js
+// The Module object: Our interface to the outside world. We import
+// and export values on it. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(moduleArg) => Promise<Module>
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to check if Module already exists (e.g. case 3 above).
+// Substitution will be replaced with actual code on later stage of the build,
+// this way Closure Compiler will not mangle it (e.g. case 4. above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module = moduleArg;
+
+// Set up the promise that indicates the Module is initialized
+var readyPromiseResolve, readyPromiseReject;
+
+var readyPromise = new Promise((resolve, reject) => {
+ readyPromiseResolve = resolve;
+ readyPromiseReject = reject;
+});
+
+// Determine the runtime environment we are in. You can customize this by
+// setting the ENVIRONMENT setting at compile time (see settings.js).
+// Attempt to auto-detect the environment
+var ENVIRONMENT_IS_WEB = typeof window == "object";
+
+var ENVIRONMENT_IS_WORKER = typeof WorkerGlobalScope != "undefined";
+
+// N.b. Electron.js environment is simultaneously a NODE-environment, but
+// also a web environment.
+var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string" && process.type != "renderer";
+
+if (ENVIRONMENT_IS_NODE) {}
+
+// --pre-jses are emitted after the Module integration code, so that they can
+// refer to Module (if they choose; they can also define Module)
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = Object.assign({}, Module);
+
+var arguments_ = [];
+
+var thisProgram = "./this.program";
+
+var quit_ = (status, toThrow) => {
+ throw toThrow;
+};
+
+// `/` should be present at the end if `scriptDirectory` is not empty
+var scriptDirectory = "";
+
+function locateFile(path) {
+ if (Module["locateFile"]) {
+ return Module["locateFile"](path, scriptDirectory);
+ }
+ return scriptDirectory + path;
+}
+
+// Hooks that are implemented differently in different runtime environments.
+var readAsync, readBinary;
+
+if (ENVIRONMENT_IS_NODE) {
+ // These modules will usually be used on Node.js. Load them eagerly to avoid
+ // the complexity of lazy-loading.
+ var fs = require("fs");
+ var nodePath = require("path");
+ scriptDirectory = __dirname + "/";
+ // include: node_shell_read.js
+ readBinary = filename => {
+ // We need to re-wrap `file://` strings to URLs. Normalizing isn't
+ // necessary in that case, the path should already be absolute.
+ filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
+ var ret = fs.readFileSync(filename);
+ return ret;
+ };
+ readAsync = (filename, binary = true) => {
+ // See the comment in the `readBinary` function.
+ filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
+ return new Promise((resolve, reject) => {
+ fs.readFile(filename, binary ? undefined : "utf8", (err, data) => {
+ if (err) reject(err); else resolve(binary ? data.buffer : data);
+ });
+ });
+ };
+ // end include: node_shell_read.js
+ if (!Module["thisProgram"] && process.argv.length > 1) {
+ thisProgram = process.argv[1].replace(/\\/g, "/");
+ }
+ arguments_ = process.argv.slice(2);
+ // MODULARIZE will export the module in the proper place outside, we don't need to export here
+ quit_ = (status, toThrow) => {
+ process.exitCode = status;
+ throw toThrow;
+ };
+} else // Note that this includes Node.js workers when relevant (pthreads is enabled).
+// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
+// ENVIRONMENT_IS_NODE.
+if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+ if (ENVIRONMENT_IS_WORKER) {
+ // Check worker, not web, since window could be polyfilled
+ scriptDirectory = self.location.href;
+ } else if (typeof document != "undefined" && document.currentScript) {
+ // web
+ scriptDirectory = document.currentScript.src;
+ }
+ // When MODULARIZE, this JS may be executed later, after document.currentScript
+ // is gone, so we saved it, and we use it here instead of any other info.
+ if (_scriptName) {
+ scriptDirectory = _scriptName;
+ }
+ // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
+ // otherwise, slice off the final part of the url to find the script directory.
+ // if scriptDirectory does not contain a slash, lastIndexOf will return -1,
+ // and scriptDirectory will correctly be replaced with an empty string.
+ // If scriptDirectory contains a query (starting with ?) or a fragment (starting with #),
+ // they are removed because they could contain a slash.
+ if (scriptDirectory.startsWith("blob:")) {
+ scriptDirectory = "";
+ } else {
+ scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1);
+ }
+ {
+ // include: web_or_worker_shell_read.js
+ if (ENVIRONMENT_IS_WORKER) {
+ readBinary = url => {
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", url, false);
+ xhr.responseType = "arraybuffer";
+ xhr.send(null);
+ return new Uint8Array(/** @type{!ArrayBuffer} */ (xhr.response));
+ };
+ }
+ readAsync = url => {
+ // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url.
+ // See https://github.com/github/fetch/pull/92#issuecomment-140665932
+ // Cordova or Electron apps are typically loaded from a file:// url.
+ // So use XHR on webview if URL is a file URL.
+ if (isFileURI(url)) {
+ return new Promise((resolve, reject) => {
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", url, true);
+ xhr.responseType = "arraybuffer";
+ xhr.onload = () => {
+ if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {
+ // file URLs can return 0
+ resolve(xhr.response);
+ return;
+ }
+ reject(xhr.status);
+ };
+ xhr.onerror = reject;
+ xhr.send(null);
+ });
+ }
+ return fetch(url, {
+ credentials: "same-origin"
+ }).then(response => {
+ if (response.ok) {
+ return response.arrayBuffer();
+ }
+ return Promise.reject(new Error(response.status + " : " + response.url));
+ });
+ };
+ }
+} else // end include: web_or_worker_shell_read.js
+{}
+
+var out = Module["print"] || console.log.bind(console);
+
+var err = Module["printErr"] || console.error.bind(console);
+
+// Merge back in the overrides
+Object.assign(Module, moduleOverrides);
+
+// Free the object hierarchy contained in the overrides, this lets the GC
+// reclaim data used.
+moduleOverrides = null;
+
+// Emit code to handle expected values on the Module object. This applies Module.x
+// to the proper local x. This has two benefits: first, we only emit it if it is
+// expected to arrive, and second, by using a local everywhere else that can be
+// minified.
+if (Module["arguments"]) arguments_ = Module["arguments"];
+
+if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
+
+// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
+// end include: shell.js
+// include: preamble.js
+// === Preamble library stuff ===
+// Documentation for the public APIs defined in this file must be updated in:
+// site/source/docs/api_reference/preamble.js.rst
+// A prebuilt local version of the documentation is available at:
+// site/build/text/docs/api_reference/preamble.js.txt
+// You can also build docs locally as HTML or other formats in site/
+// An online HTML version (which may be of a different version of Emscripten)
+// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
+var wasmBinary = Module["wasmBinary"];
+
+// Wasm globals
+var wasmMemory;
+
+//========================================
+// Runtime essentials
+//========================================
+// whether we are quitting the application. no code should run after this.
+// set in exit() and abort()
+var ABORT = false;
+
+// set by exit() and abort(). Passed to 'onExit' handler.
+// NOTE: This is also used as the process return code code in shell environments
+// but only when noExitRuntime is false.
+var EXITSTATUS;
+
+// Memory management
+var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64;
+
+// include: runtime_shared.js
+function updateMemoryViews() {
+ var b = wasmMemory.buffer;
+ Module["HEAP8"] = HEAP8 = new Int8Array(b);
+ Module["HEAP16"] = HEAP16 = new Int16Array(b);
+ Module["HEAPU8"] = HEAPU8 = new Uint8Array(b);
+ Module["HEAPU16"] = HEAPU16 = new Uint16Array(b);
+ Module["HEAP32"] = HEAP32 = new Int32Array(b);
+ Module["HEAPU32"] = HEAPU32 = new Uint32Array(b);
+ Module["HEAPF32"] = HEAPF32 = new Float32Array(b);
+ Module["HEAPF64"] = HEAPF64 = new Float64Array(b);
+}
+
+// end include: runtime_shared.js
+// include: runtime_stack_check.js
+// end include: runtime_stack_check.js
+var __ATPRERUN__ = [];
+
+// functions called before the runtime is initialized
+var __ATINIT__ = [];
+
+// functions called during startup
+var __ATMAIN__ = [];
+
+// functions called during shutdown
+var __ATPOSTRUN__ = [];
+
+// functions called after the main() is called
+var runtimeInitialized = false;
+
+function preRun() {
+ if (Module["preRun"]) {
+ if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ];
+ while (Module["preRun"].length) {
+ addOnPreRun(Module["preRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function initRuntime() {
+ runtimeInitialized = true;
+ if (!Module["noFSInit"] && !FS.initialized) FS.init();
+ FS.ignorePermissions = false;
+ TTY.init();
+ callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+ callRuntimeCallbacks(__ATMAIN__);
+}
+
+function postRun() {
+ if (Module["postRun"]) {
+ if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ];
+ while (Module["postRun"].length) {
+ addOnPostRun(Module["postRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+ __ATPRERUN__.unshift(cb);
+}
+
+function addOnInit(cb) {
+ __ATINIT__.unshift(cb);
+}
+
+function addOnPostRun(cb) {
+ __ATPOSTRUN__.unshift(cb);
+}
+
+// include: runtime_math.js
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
+// end include: runtime_math.js
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// Module.preRun (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+
+var runDependencyWatcher = null;
+
+var dependenciesFulfilled = null;
+
+// overridden to take different actions when all run dependencies are fulfilled
+function getUniqueRunDependency(id) {
+ return id;
+}
+
+function addRunDependency(id) {
+ runDependencies++;
+ Module["monitorRunDependencies"]?.(runDependencies);
+}
+
+function removeRunDependency(id) {
+ runDependencies--;
+ Module["monitorRunDependencies"]?.(runDependencies);
+ if (runDependencies == 0) {
+ if (runDependencyWatcher !== null) {
+ clearInterval(runDependencyWatcher);
+ runDependencyWatcher = null;
+ }
+ if (dependenciesFulfilled) {
+ var callback = dependenciesFulfilled;
+ dependenciesFulfilled = null;
+ callback();
+ }
+ }
+}
+
+/** @param {string|number=} what */ function abort(what) {
+ Module["onAbort"]?.(what);
+ what = "Aborted(" + what + ")";
+ // TODO(sbc): Should we remove printing and leave it up to whoever
+ // catches the exception?
+ err(what);
+ ABORT = true;
+ what += ". Build with -sASSERTIONS for more info.";
+ // Use a wasm runtime error, because a JS error might be seen as a foreign
+ // exception, which means we'd run destructors on it. We need the error to
+ // simply make the program stop.
+ // FIXME This approach does not work in Wasm EH because it currently does not assume
+ // all RuntimeErrors are from traps; it decides whether a RuntimeError is from
+ // a trap or not based on a hidden field within the object. So at the moment
+ // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that
+ // allows this in the wasm spec.
+ // Suppress closure compiler warning here. Closure compiler's builtin extern
+ // definition for WebAssembly.RuntimeError claims it takes no arguments even
+ // though it can.
+ // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
+ /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what);
+ readyPromiseReject(e);
+ // Throw the error whether or not MODULARIZE is set because abort is used
+ // in code paths apart from instantiation where an exception is expected
+ // to be thrown when abort is called.
+ throw e;
+}
+
+// include: memoryprofiler.js
+// end include: memoryprofiler.js
+// include: URIUtils.js
+// Prefix of data URIs emitted by SINGLE_FILE and related options.
+var dataURIPrefix = "data:application/octet-stream;base64,";
+
+/**
+ * Indicates whether filename is a base64 data URI.
+ * @noinline
+ */ var isDataURI = filename => filename.startsWith(dataURIPrefix);
+
+/**
+ * Indicates whether filename is delivered via file protocol (as opposed to http/https)
+ * @noinline
+ */ var isFileURI = filename => filename.startsWith("file://");
+
+// end include: URIUtils.js
+// include: runtime_exceptions.js
+// end include: runtime_exceptions.js
+function findWasmBinary() {
+ var f = "gcc-loops.wasm";
+ if (!isDataURI(f)) {
+ return locateFile(f);
+ }
+ return f;
+}
+
+var wasmBinaryFile;
+
+function getBinarySync(file) {
+ if (file == wasmBinaryFile && wasmBinary) {
+ return new Uint8Array(wasmBinary);
+ }
+ if (readBinary) {
+ return readBinary(file);
+ }
+ throw "both async and sync fetching of the wasm failed";
+}
+
+function getBinaryPromise(binaryFile) {
+ // If we don't have the binary yet, load it asynchronously using readAsync.
+ if (!wasmBinary) {
+ // Fetch the binary using readAsync
+ return readAsync(binaryFile).then(response => new Uint8Array(/** @type{!ArrayBuffer} */ (response)), // Fall back to getBinarySync if readAsync fails
+ () => getBinarySync(binaryFile));
+ }
+ // Otherwise, getBinarySync should be able to get it synchronously
+ return Promise.resolve().then(() => getBinarySync(binaryFile));
+}
+
+function instantiateArrayBuffer(binaryFile, imports, receiver) {
+ return getBinaryPromise(binaryFile).then(binary => WebAssembly.instantiate(binary, imports)).then(receiver, reason => {
+ err(`failed to asynchronously prepare wasm: ${reason}`);
+ abort(reason);
+ });
+}
+
+function instantiateAsync(binary, binaryFile, imports, callback) {
+ if (!binary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(binaryFile) && // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously.
+ !isFileURI(binaryFile) && // Avoid instantiateStreaming() on Node.js environment for now, as while
+ // Node.js v18.1.0 implements it, it does not have a full fetch()
+ // implementation yet.
+ // Reference:
+ // https://github.com/emscripten-core/emscripten/pull/16917
+ !ENVIRONMENT_IS_NODE && typeof fetch == "function") {
+ return fetch(binaryFile, {
+ credentials: "same-origin"
+ }).then(response => {
+ // Suppress closure warning here since the upstream definition for
+ // instantiateStreaming only allows Promise<Repsponse> rather than
+ // an actual Response.
+ // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed.
+ /** @suppress {checkTypes} */ var result = WebAssembly.instantiateStreaming(response, imports);
+ return result.then(callback, function(reason) {
+ // We expect the most common failure cause to be a bad MIME type for the binary,
+ // in which case falling back to ArrayBuffer instantiation should work.
+ err(`wasm streaming compile failed: ${reason}`);
+ err("falling back to ArrayBuffer instantiation");
+ return instantiateArrayBuffer(binaryFile, imports, callback);
+ });
+ });
+ }
+ return instantiateArrayBuffer(binaryFile, imports, callback);
+}
+
+function getWasmImports() {
+ // prepare imports
+ return {
+ "env": wasmImports,
+ "wasi_snapshot_preview1": wasmImports
+ };
+}
+
+// Create the wasm instance.
+// Receives the wasm imports, returns the exports.
+function createWasm() {
+ // Load the wasm module and create an instance of using native support in the JS engine.
+ // handle a generated wasm instance, receiving its exports and
+ // performing other necessary setup
+ /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) {
+ wasmExports = instance.exports;
+ wasmMemory = wasmExports["memory"];
+ updateMemoryViews();
+ addOnInit(wasmExports["__wasm_call_ctors"]);
+ removeRunDependency("wasm-instantiate");
+ return wasmExports;
+ }
+ // wait for the pthread pool (if any)
+ addRunDependency("wasm-instantiate");
+ // Prefer streaming instantiation if available.
+ function receiveInstantiationResult(result) {
+ // 'result' is a ResultObject object which has both the module and instance.
+ // receiveInstance() will swap in the exports (to Module.asm) so they can be called
+ // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
+ // When the regression is fixed, can restore the above PTHREADS-enabled path.
+ receiveInstance(result["instance"]);
+ }
+ var info = getWasmImports();
+ // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
+ // to manually instantiate the Wasm module themselves. This allows pages to
+ // run the instantiation parallel to any other async startup actions they are
+ // performing.
+ // Also pthreads and wasm workers initialize the wasm instance through this
+ // path.
+ if (Module["instantiateWasm"]) {
+ try {
+ return Module["instantiateWasm"](info, receiveInstance);
+ } catch (e) {
+ err(`Module.instantiateWasm callback failed with error: ${e}`);
+ // If instantiation fails, reject the module ready promise.
+ readyPromiseReject(e);
+ }
+ }
+ wasmBinaryFile ??= findWasmBinary();
+ // If instantiation fails, reject the module ready promise.
+ instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject);
+ return {};
+}
+
+// Globals used by JS i64 conversions (see makeSetValue)
+var tempDouble;
+
+var tempI64;
+
+// include: runtime_debug.js
+// end include: runtime_debug.js
+// === Body ===
+// end include: preamble.js
+class ExitStatus {
+ name="ExitStatus";
+ constructor(status) {
+ this.message = `Program terminated with exit(${status})`;
+ this.status = status;
+ }
+}
+
+var callRuntimeCallbacks = callbacks => {
+ while (callbacks.length > 0) {
+ // Pass the module as the first argument.
+ callbacks.shift()(Module);
+ }
+};
+
+var noExitRuntime = Module["noExitRuntime"] || true;
+
+class ExceptionInfo {
+ // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it.
+ constructor(excPtr) {
+ this.excPtr = excPtr;
+ this.ptr = excPtr - 24;
+ }
+ set_type(type) {
+ HEAPU32[(((this.ptr) + (4)) >> 2)] = type;
+ }
+ get_type() {
+ return HEAPU32[(((this.ptr) + (4)) >> 2)];
+ }
+ set_destructor(destructor) {
+ HEAPU32[(((this.ptr) + (8)) >> 2)] = destructor;
+ }
+ get_destructor() {
+ return HEAPU32[(((this.ptr) + (8)) >> 2)];
+ }
+ set_caught(caught) {
+ caught = caught ? 1 : 0;
+ HEAP8[(this.ptr) + (12)] = caught;
+ }
+ get_caught() {
+ return HEAP8[(this.ptr) + (12)] != 0;
+ }
+ set_rethrown(rethrown) {
+ rethrown = rethrown ? 1 : 0;
+ HEAP8[(this.ptr) + (13)] = rethrown;
+ }
+ get_rethrown() {
+ return HEAP8[(this.ptr) + (13)] != 0;
+ }
+ // Initialize native structure fields. Should be called once after allocated.
+ init(type, destructor) {
+ this.set_adjusted_ptr(0);
+ this.set_type(type);
+ this.set_destructor(destructor);
+ }
+ set_adjusted_ptr(adjustedPtr) {
+ HEAPU32[(((this.ptr) + (16)) >> 2)] = adjustedPtr;
+ }
+ get_adjusted_ptr() {
+ return HEAPU32[(((this.ptr) + (16)) >> 2)];
+ }
+}
+
+var exceptionLast = 0;
+
+var uncaughtExceptionCount = 0;
+
+var ___cxa_throw = (ptr, type, destructor) => {
+ var info = new ExceptionInfo(ptr);
+ // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception.
+ info.init(type, destructor);
+ exceptionLast = ptr;
+ uncaughtExceptionCount++;
+ throw exceptionLast;
+};
+
+var __abort_js = () => abort("");
+
+var __emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num);
+
+var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
+ // Parameter maxBytesToWrite is not optional. Negative values, 0, null,
+ // undefined and false each don't write out any bytes.
+ if (!(maxBytesToWrite > 0)) return 0;
+ var startIdx = outIdx;
+ var endIdx = outIdx + maxBytesToWrite - 1;
+ // -1 for string null terminator.
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
+ // unit, not a Unicode code point of the character! So decode
+ // UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description
+ // and https://www.ietf.org/rfc/rfc2279.txt
+ // and https://tools.ietf.org/html/rfc3629
+ var u = str.charCodeAt(i);
+ // possibly a lead surrogate
+ if (u >= 55296 && u <= 57343) {
+ var u1 = str.charCodeAt(++i);
+ u = 65536 + ((u & 1023) << 10) | (u1 & 1023);
+ }
+ if (u <= 127) {
+ if (outIdx >= endIdx) break;
+ heap[outIdx++] = u;
+ } else if (u <= 2047) {
+ if (outIdx + 1 >= endIdx) break;
+ heap[outIdx++] = 192 | (u >> 6);
+ heap[outIdx++] = 128 | (u & 63);
+ } else if (u <= 65535) {
+ if (outIdx + 2 >= endIdx) break;
+ heap[outIdx++] = 224 | (u >> 12);
+ heap[outIdx++] = 128 | ((u >> 6) & 63);
+ heap[outIdx++] = 128 | (u & 63);
+ } else {
+ if (outIdx + 3 >= endIdx) break;
+ heap[outIdx++] = 240 | (u >> 18);
+ heap[outIdx++] = 128 | ((u >> 12) & 63);
+ heap[outIdx++] = 128 | ((u >> 6) & 63);
+ heap[outIdx++] = 128 | (u & 63);
+ }
+ }
+ // Null-terminate the pointer to the buffer.
+ heap[outIdx] = 0;
+ return outIdx - startIdx;
+};
+
+var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
+
+var __tzset_js = (timezone, daylight, std_name, dst_name) => {
+ // TODO: Use (malleable) environment variables instead of system settings.
+ var currentYear = (new Date).getFullYear();
+ var winter = new Date(currentYear, 0, 1);
+ var summer = new Date(currentYear, 6, 1);
+ var winterOffset = winter.getTimezoneOffset();
+ var summerOffset = summer.getTimezoneOffset();
+ // Local standard timezone offset. Local standard time is not adjusted for
+ // daylight savings. This code uses the fact that getTimezoneOffset returns
+ // a greater value during Standard Time versus Daylight Saving Time (DST).
+ // Thus it determines the expected output during Standard Time, and it
+ // compares whether the output of the given date the same (Standard) or less
+ // (DST).
+ var stdTimezoneOffset = Math.max(winterOffset, summerOffset);
+ // timezone is specified as seconds west of UTC ("The external variable
+ // `timezone` shall be set to the difference, in seconds, between
+ // Coordinated Universal Time (UTC) and local standard time."), the same
+ // as returned by stdTimezoneOffset.
+ // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html
+ HEAPU32[((timezone) >> 2)] = stdTimezoneOffset * 60;
+ HEAP32[((daylight) >> 2)] = Number(winterOffset != summerOffset);
+ var extractZone = timezoneOffset => {
+ // Why inverse sign?
+ // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
+ var sign = timezoneOffset >= 0 ? "-" : "+";
+ var absOffset = Math.abs(timezoneOffset);
+ var hours = String(Math.floor(absOffset / 60)).padStart(2, "0");
+ var minutes = String(absOffset % 60).padStart(2, "0");
+ return `UTC${sign}${hours}${minutes}`;
+ };
+ var winterName = extractZone(winterOffset);
+ var summerName = extractZone(summerOffset);
+ if (summerOffset < winterOffset) {
+ // Northern hemisphere
+ stringToUTF8(winterName, std_name, 17);
+ stringToUTF8(summerName, dst_name, 17);
+ } else {
+ stringToUTF8(winterName, dst_name, 17);
+ stringToUTF8(summerName, std_name, 17);
+ }
+};
+
+var _emscripten_date_now = () => Date.now();
+
+var abortOnCannotGrowMemory = requestedSize => {
+ abort("OOM");
+};
+
+var _emscripten_resize_heap = requestedSize => {
+ var oldSize = HEAPU8.length;
+ // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
+ requestedSize >>>= 0;
+ abortOnCannotGrowMemory(requestedSize);
+};
+
+var ENV = {};
+
+var getExecutableName = () => thisProgram || "./this.program";
+
+var getEnvStrings = () => {
+ if (!getEnvStrings.strings) {
+ // Default values.
+ // Browser language detection #8751
+ var lang = ((typeof navigator == "object" && navigator.languages && navigator.languages[0]) || "C").replace("-", "_") + ".UTF-8";
+ var env = {
+ "USER": "web_user",
+ "LOGNAME": "web_user",
+ "PATH": "/",
+ "PWD": "/",
+ "HOME": "/home/web_user",
+ "LANG": lang,
+ "_": getExecutableName()
+ };
+ // Apply the user-provided values, if any.
+ for (var x in ENV) {
+ // x is a key in ENV; if ENV[x] is undefined, that means it was
+ // explicitly set to be so. We allow user code to do that to
+ // force variables with default values to remain unset.
+ if (ENV[x] === undefined) delete env[x]; else env[x] = ENV[x];
+ }
+ var strings = [];
+ for (var x in env) {
+ strings.push(`${x}=${env[x]}`);
+ }
+ getEnvStrings.strings = strings;
+ }
+ return getEnvStrings.strings;
+};
+
+var stringToAscii = (str, buffer) => {
+ for (var i = 0; i < str.length; ++i) {
+ HEAP8[buffer++] = str.charCodeAt(i);
+ }
+ // Null-terminate the string
+ HEAP8[buffer] = 0;
+};
+
+var _environ_get = (__environ, environ_buf) => {
+ var bufSize = 0;
+ getEnvStrings().forEach((string, i) => {
+ var ptr = environ_buf + bufSize;
+ HEAPU32[(((__environ) + (i * 4)) >> 2)] = ptr;
+ stringToAscii(string, ptr);
+ bufSize += string.length + 1;
+ });
+ return 0;
+};
+
+var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
+ var strings = getEnvStrings();
+ HEAPU32[((penviron_count) >> 2)] = strings.length;
+ var bufSize = 0;
+ strings.forEach(string => bufSize += string.length + 1);
+ HEAPU32[((penviron_buf_size) >> 2)] = bufSize;
+ return 0;
+};
+
+var PATH = {
+ isAbs: path => path.charAt(0) === "/",
+ splitPath: filename => {
+ var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+ return splitPathRe.exec(filename).slice(1);
+ },
+ normalizeArray: (parts, allowAboveRoot) => {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === ".") {
+ parts.splice(i, 1);
+ } else if (last === "..") {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (;up; up--) {
+ parts.unshift("..");
+ }
+ }
+ return parts;
+ },
+ normalize: path => {
+ var isAbsolute = PATH.isAbs(path), trailingSlash = path.substr(-1) === "/";
+ // Normalize the path
+ path = PATH.normalizeArray(path.split("/").filter(p => !!p), !isAbsolute).join("/");
+ if (!path && !isAbsolute) {
+ path = ".";
+ }
+ if (path && trailingSlash) {
+ path += "/";
+ }
+ return (isAbsolute ? "/" : "") + path;
+ },
+ dirname: path => {
+ var result = PATH.splitPath(path), root = result[0], dir = result[1];
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return ".";
+ }
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+ return root + dir;
+ },
+ basename: path => {
+ // EMSCRIPTEN return '/'' for '/', not an empty string
+ if (path === "/") return "/";
+ path = PATH.normalize(path);
+ path = path.replace(/\/$/, "");
+ var lastSlash = path.lastIndexOf("/");
+ if (lastSlash === -1) return path;
+ return path.substr(lastSlash + 1);
+ },
+ join: (...paths) => PATH.normalize(paths.join("/")),
+ join2: (l, r) => PATH.normalize(l + "/" + r)
+};
+
+var initRandomFill = () => {
+ if (typeof crypto == "object" && typeof crypto["getRandomValues"] == "function") {
+ // for modern web browsers
+ return view => crypto.getRandomValues(view);
+ } else if (ENVIRONMENT_IS_NODE) {
+ // for nodejs with or without crypto support included
+ try {
+ var crypto_module = require("crypto");
+ var randomFillSync = crypto_module["randomFillSync"];
+ if (randomFillSync) {
+ // nodejs with LTS crypto support
+ return view => crypto_module["randomFillSync"](view);
+ }
+ // very old nodejs with the original crypto API
+ var randomBytes = crypto_module["randomBytes"];
+ return view => (view.set(randomBytes(view.byteLength)), // Return the original view to match modern native implementations.
+ view);
+ } catch (e) {}
+ }
+ // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096
+ abort("initRandomDevice");
+};
+
+var randomFill = view => (randomFill = initRandomFill())(view);
+
+var PATH_FS = {
+ resolve: (...args) => {
+ var resolvedPath = "", resolvedAbsolute = false;
+ for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? args[i] : FS.cwd();
+ // Skip empty and invalid entries
+ if (typeof path != "string") {
+ throw new TypeError("Arguments to path.resolve must be strings");
+ } else if (!path) {
+ return "";
+ }
+ // an invalid portion invalidates the whole thing
+ resolvedPath = path + "/" + resolvedPath;
+ resolvedAbsolute = PATH.isAbs(path);
+ }
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+ resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(p => !!p), !resolvedAbsolute).join("/");
+ return ((resolvedAbsolute ? "/" : "") + resolvedPath) || ".";
+ },
+ relative: (from, to) => {
+ from = PATH_FS.resolve(from).substr(1);
+ to = PATH_FS.resolve(to).substr(1);
+ function trim(arr) {
+ var start = 0;
+ for (;start < arr.length; start++) {
+ if (arr[start] !== "") break;
+ }
+ var end = arr.length - 1;
+ for (;end >= 0; end--) {
+ if (arr[end] !== "") break;
+ }
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+ var fromParts = trim(from.split("/"));
+ var toParts = trim(to.split("/"));
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push("..");
+ }
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+ return outputParts.join("/");
+ }
+};
+
+var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder : undefined;
+
+/**
+ * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given
+ * array that contains uint8 values, returns a copy of that string as a
+ * Javascript String object.
+ * heapOrArray is either a regular array, or a JavaScript typed array view.
+ * @param {number=} idx
+ * @param {number=} maxBytesToRead
+ * @return {string}
+ */ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => {
+ var endIdx = idx + maxBytesToRead;
+ var endPtr = idx;
+ // TextDecoder needs to know the byte length in advance, it doesn't stop on
+ // null terminator by itself. Also, use the length info to avoid running tiny
+ // strings through TextDecoder, since .subarray() allocates garbage.
+ // (As a tiny code save trick, compare endPtr against endIdx using a negation,
+ // so that undefined/NaN means Infinity)
+ while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
+ if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
+ return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
+ }
+ var str = "";
+ // If building with TextDecoder, we have already computed the string length
+ // above, so test loop end condition against that
+ while (idx < endPtr) {
+ // For UTF8 byte structure, see:
+ // http://en.wikipedia.org/wiki/UTF-8#Description
+ // https://www.ietf.org/rfc/rfc2279.txt
+ // https://tools.ietf.org/html/rfc3629
+ var u0 = heapOrArray[idx++];
+ if (!(u0 & 128)) {
+ str += String.fromCharCode(u0);
+ continue;
+ }
+ var u1 = heapOrArray[idx++] & 63;
+ if ((u0 & 224) == 192) {
+ str += String.fromCharCode(((u0 & 31) << 6) | u1);
+ continue;
+ }
+ var u2 = heapOrArray[idx++] & 63;
+ if ((u0 & 240) == 224) {
+ u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
+ } else {
+ u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
+ }
+ if (u0 < 65536) {
+ str += String.fromCharCode(u0);
+ } else {
+ var ch = u0 - 65536;
+ str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));
+ }
+ }
+ return str;
+};
+
+var FS_stdin_getChar_buffer = [];
+
+var lengthBytesUTF8 = str => {
+ var len = 0;
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
+ // unit, not a Unicode code point of the character! So decode
+ // UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ var c = str.charCodeAt(i);
+ // possibly a lead surrogate
+ if (c <= 127) {
+ len++;
+ } else if (c <= 2047) {
+ len += 2;
+ } else if (c >= 55296 && c <= 57343) {
+ len += 4;
+ ++i;
+ } else {
+ len += 3;
+ }
+ }
+ return len;
+};
+
+/** @type {function(string, boolean=, number=)} */ function intArrayFromString(stringy, dontAddNull, length) {
+ var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1;
+ var u8array = new Array(len);
+ var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
+ if (dontAddNull) u8array.length = numBytesWritten;
+ return u8array;
+}
+
+var FS_stdin_getChar = () => {
+ if (!FS_stdin_getChar_buffer.length) {
+ var result = null;
+ if (ENVIRONMENT_IS_NODE) {
+ // we will read data by chunks of BUFSIZE
+ var BUFSIZE = 256;
+ var buf = Buffer.alloc(BUFSIZE);
+ var bytesRead = 0;
+ // For some reason we must suppress a closure warning here, even though
+ // fd definitely exists on process.stdin, and is even the proper way to
+ // get the fd of stdin,
+ // https://github.com/nodejs/help/issues/2136#issuecomment-523649904
+ // This started to happen after moving this logic out of library_tty.js,
+ // so it is related to the surrounding code in some unclear manner.
+ /** @suppress {missingProperties} */ var fd = process.stdin.fd;
+ try {
+ bytesRead = fs.readSync(fd, buf, 0, BUFSIZE);
+ } catch (e) {
+ // Cross-platform differences: on Windows, reading EOF throws an
+ // exception, but on other OSes, reading EOF returns 0. Uniformize
+ // behavior by treating the EOF exception to return 0.
+ if (e.toString().includes("EOF")) bytesRead = 0; else throw e;
+ }
+ if (bytesRead > 0) {
+ result = buf.slice(0, bytesRead).toString("utf-8");
+ }
+ } else if (typeof window != "undefined" && typeof window.prompt == "function") {
+ // Browser.
+ result = window.prompt("Input: ");
+ // returns null on cancel
+ if (result !== null) {
+ result += "\n";
+ }
+ } else {}
+ if (!result) {
+ return null;
+ }
+ FS_stdin_getChar_buffer = intArrayFromString(result, true);
+ }
+ return FS_stdin_getChar_buffer.shift();
+};
+
+var TTY = {
+ ttys: [],
+ init() {},
+ // https://github.com/emscripten-core/emscripten/pull/1555
+ // if (ENVIRONMENT_IS_NODE) {
+ // // currently, FS.init does not distinguish if process.stdin is a file or TTY
+ // // device, it always assumes it's a TTY device. because of this, we're forcing
+ // // process.stdin to UTF8 encoding to at least make stdin reading compatible
+ // // with text files until FS.init can be refactored.
+ // process.stdin.setEncoding('utf8');
+ // }
+ shutdown() {},
+ // https://github.com/emscripten-core/emscripten/pull/1555
+ // if (ENVIRONMENT_IS_NODE) {
+ // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+ // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+ // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+ // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+ // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+ // process.stdin.pause();
+ // }
+ register(dev, ops) {
+ TTY.ttys[dev] = {
+ input: [],
+ output: [],
+ ops
+ };
+ FS.registerDevice(dev, TTY.stream_ops);
+ },
+ stream_ops: {
+ open(stream) {
+ var tty = TTY.ttys[stream.node.rdev];
+ if (!tty) {
+ throw new FS.ErrnoError(43);
+ }
+ stream.tty = tty;
+ stream.seekable = false;
+ },
+ close(stream) {
+ // flush any pending line data
+ stream.tty.ops.fsync(stream.tty);
+ },
+ fsync(stream) {
+ stream.tty.ops.fsync(stream.tty);
+ },
+ read(stream, buffer, offset, length, pos) {
+ /* ignored */ if (!stream.tty || !stream.tty.ops.get_char) {
+ throw new FS.ErrnoError(60);
+ }
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = stream.tty.ops.get_char(stream.tty);
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(6);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset + i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, pos) {
+ if (!stream.tty || !stream.tty.ops.put_char) {
+ throw new FS.ErrnoError(60);
+ }
+ try {
+ for (var i = 0; i < length; i++) {
+ stream.tty.ops.put_char(stream.tty, buffer[offset + i]);
+ }
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ },
+ default_tty_ops: {
+ get_char(tty) {
+ return FS_stdin_getChar();
+ },
+ put_char(tty, val) {
+ if (val === null || val === 10) {
+ out(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ } else {
+ if (val != 0) tty.output.push(val);
+ }
+ },
+ // val == 0 would cut text output off in the middle.
+ fsync(tty) {
+ if (tty.output && tty.output.length > 0) {
+ out(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ }
+ },
+ ioctl_tcgets(tty) {
+ // typical setting
+ return {
+ c_iflag: 25856,
+ c_oflag: 5,
+ c_cflag: 191,
+ c_lflag: 35387,
+ c_cc: [ 3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ };
+ },
+ ioctl_tcsets(tty, optional_actions, data) {
+ // currently just ignore
+ return 0;
+ },
+ ioctl_tiocgwinsz(tty) {
+ return [ 24, 80 ];
+ }
+ },
+ default_tty1_ops: {
+ put_char(tty, val) {
+ if (val === null || val === 10) {
+ err(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ } else {
+ if (val != 0) tty.output.push(val);
+ }
+ },
+ fsync(tty) {
+ if (tty.output && tty.output.length > 0) {
+ err(UTF8ArrayToString(tty.output));
+ tty.output = [];
+ }
+ }
+ }
+};
+
+var mmapAlloc = size => {
+ abort();
+};
+
+var MEMFS = {
+ ops_table: null,
+ mount(mount) {
+ return MEMFS.createNode(null, "/", 16895, 0);
+ },
+ createNode(parent, name, mode, dev) {
+ if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+ // no supported
+ throw new FS.ErrnoError(63);
+ }
+ MEMFS.ops_table ||= {
+ dir: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ lookup: MEMFS.node_ops.lookup,
+ mknod: MEMFS.node_ops.mknod,
+ rename: MEMFS.node_ops.rename,
+ unlink: MEMFS.node_ops.unlink,
+ rmdir: MEMFS.node_ops.rmdir,
+ readdir: MEMFS.node_ops.readdir,
+ symlink: MEMFS.node_ops.symlink
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek
+ }
+ },
+ file: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek,
+ read: MEMFS.stream_ops.read,
+ write: MEMFS.stream_ops.write,
+ allocate: MEMFS.stream_ops.allocate,
+ mmap: MEMFS.stream_ops.mmap,
+ msync: MEMFS.stream_ops.msync
+ }
+ },
+ link: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ readlink: MEMFS.node_ops.readlink
+ },
+ stream: {}
+ },
+ chrdev: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: FS.chrdev_stream_ops
+ }
+ };
+ var node = FS.createNode(parent, name, mode, dev);
+ if (FS.isDir(node.mode)) {
+ node.node_ops = MEMFS.ops_table.dir.node;
+ node.stream_ops = MEMFS.ops_table.dir.stream;
+ node.contents = {};
+ } else if (FS.isFile(node.mode)) {
+ node.node_ops = MEMFS.ops_table.file.node;
+ node.stream_ops = MEMFS.ops_table.file.stream;
+ node.usedBytes = 0;
+ // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.
+ // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred
+ // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size
+ // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme.
+ node.contents = null;
+ } else if (FS.isLink(node.mode)) {
+ node.node_ops = MEMFS.ops_table.link.node;
+ node.stream_ops = MEMFS.ops_table.link.stream;
+ } else if (FS.isChrdev(node.mode)) {
+ node.node_ops = MEMFS.ops_table.chrdev.node;
+ node.stream_ops = MEMFS.ops_table.chrdev.stream;
+ }
+ node.timestamp = Date.now();
+ // add the new node to the parent
+ if (parent) {
+ parent.contents[name] = node;
+ parent.timestamp = node.timestamp;
+ }
+ return node;
+ },
+ getFileDataAsTypedArray(node) {
+ if (!node.contents) return new Uint8Array(0);
+ if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes);
+ // Make sure to not return excess unused bytes.
+ return new Uint8Array(node.contents);
+ },
+ expandFileStorage(node, newCapacity) {
+ var prevCapacity = node.contents ? node.contents.length : 0;
+ if (prevCapacity >= newCapacity) return;
+ // No need to expand, the storage was already large enough.
+ // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity.
+ // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to
+ // avoid overshooting the allocation cap by a very large margin.
+ var CAPACITY_DOUBLING_MAX = 1024 * 1024;
+ newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>> 0);
+ if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);
+ // At minimum allocate 256b for each file when expanding.
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newCapacity);
+ // Allocate new storage.
+ if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0);
+ },
+ // Copy old data over to the new storage.
+ resizeFileStorage(node, newSize) {
+ if (node.usedBytes == newSize) return;
+ if (newSize == 0) {
+ node.contents = null;
+ // Fully decommit when requesting a resize to zero.
+ node.usedBytes = 0;
+ } else {
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newSize);
+ // Allocate new storage.
+ if (oldContents) {
+ node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes)));
+ }
+ // Copy old data over to the new storage.
+ node.usedBytes = newSize;
+ }
+ },
+ node_ops: {
+ getattr(node) {
+ var attr = {};
+ // device numbers reuse inode numbers.
+ attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+ attr.ino = node.id;
+ attr.mode = node.mode;
+ attr.nlink = 1;
+ attr.uid = 0;
+ attr.gid = 0;
+ attr.rdev = node.rdev;
+ if (FS.isDir(node.mode)) {
+ attr.size = 4096;
+ } else if (FS.isFile(node.mode)) {
+ attr.size = node.usedBytes;
+ } else if (FS.isLink(node.mode)) {
+ attr.size = node.link.length;
+ } else {
+ attr.size = 0;
+ }
+ attr.atime = new Date(node.timestamp);
+ attr.mtime = new Date(node.timestamp);
+ attr.ctime = new Date(node.timestamp);
+ // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+ // but this is not required by the standard.
+ attr.blksize = 4096;
+ attr.blocks = Math.ceil(attr.size / attr.blksize);
+ return attr;
+ },
+ setattr(node, attr) {
+ if (attr.mode !== undefined) {
+ node.mode = attr.mode;
+ }
+ if (attr.timestamp !== undefined) {
+ node.timestamp = attr.timestamp;
+ }
+ if (attr.size !== undefined) {
+ MEMFS.resizeFileStorage(node, attr.size);
+ }
+ },
+ lookup(parent, name) {
+ throw MEMFS.doesNotExistError;
+ },
+ mknod(parent, name, mode, dev) {
+ return MEMFS.createNode(parent, name, mode, dev);
+ },
+ rename(old_node, new_dir, new_name) {
+ // if we're overwriting a directory at new_name, make sure it's empty.
+ if (FS.isDir(old_node.mode)) {
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {}
+ if (new_node) {
+ for (var i in new_node.contents) {
+ throw new FS.ErrnoError(55);
+ }
+ }
+ }
+ // do the internal rewiring
+ delete old_node.parent.contents[old_node.name];
+ old_node.parent.timestamp = Date.now();
+ old_node.name = new_name;
+ new_dir.contents[new_name] = old_node;
+ new_dir.timestamp = old_node.parent.timestamp;
+ },
+ unlink(parent, name) {
+ delete parent.contents[name];
+ parent.timestamp = Date.now();
+ },
+ rmdir(parent, name) {
+ var node = FS.lookupNode(parent, name);
+ for (var i in node.contents) {
+ throw new FS.ErrnoError(55);
+ }
+ delete parent.contents[name];
+ parent.timestamp = Date.now();
+ },
+ readdir(node) {
+ var entries = [ ".", ".." ];
+ for (var key of Object.keys(node.contents)) {
+ entries.push(key);
+ }
+ return entries;
+ },
+ symlink(parent, newname, oldpath) {
+ var node = MEMFS.createNode(parent, newname, 511 | 40960, 0);
+ node.link = oldpath;
+ return node;
+ },
+ readlink(node) {
+ if (!FS.isLink(node.mode)) {
+ throw new FS.ErrnoError(28);
+ }
+ return node.link;
+ }
+ },
+ stream_ops: {
+ read(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ if (position >= stream.node.usedBytes) return 0;
+ var size = Math.min(stream.node.usedBytes - position, length);
+ if (size > 8 && contents.subarray) {
+ // non-trivial, and typed array
+ buffer.set(contents.subarray(position, position + size), offset);
+ } else {
+ for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
+ }
+ return size;
+ },
+ write(stream, buffer, offset, length, position, canOwn) {
+ if (!length) return 0;
+ var node = stream.node;
+ node.timestamp = Date.now();
+ if (buffer.subarray && (!node.contents || node.contents.subarray)) {
+ // This write is from a typed array to a typed array?
+ if (canOwn) {
+ node.contents = buffer.subarray(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (node.usedBytes === 0 && position === 0) {
+ // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data.
+ node.contents = buffer.slice(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (position + length <= node.usedBytes) {
+ // Writing to an already allocated and used subrange of the file?
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ return length;
+ }
+ }
+ // Appending to an existing file and we need to reallocate, or source data did not come as a typed array.
+ MEMFS.expandFileStorage(node, position + length);
+ if (node.contents.subarray && buffer.subarray) {
+ // Use typed array write which is available.
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ } else {
+ for (var i = 0; i < length; i++) {
+ node.contents[position + i] = buffer[offset + i];
+ }
+ }
+ node.usedBytes = Math.max(node.usedBytes, position + length);
+ return length;
+ },
+ llseek(stream, offset, whence) {
+ var position = offset;
+ if (whence === 1) {
+ position += stream.position;
+ } else if (whence === 2) {
+ if (FS.isFile(stream.node.mode)) {
+ position += stream.node.usedBytes;
+ }
+ }
+ if (position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ return position;
+ },
+ allocate(stream, offset, length) {
+ MEMFS.expandFileStorage(stream.node, offset + length);
+ stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);
+ },
+ mmap(stream, length, position, prot, flags) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ var ptr;
+ var allocated;
+ var contents = stream.node.contents;
+ // Only make a new copy when MAP_PRIVATE is specified.
+ if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) {
+ // We can't emulate MAP_SHARED when the file is not backed by the
+ // buffer we're mapping to (e.g. the HEAP buffer).
+ allocated = false;
+ ptr = contents.byteOffset;
+ } else {
+ allocated = true;
+ ptr = mmapAlloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(48);
+ }
+ if (contents) {
+ // Try to avoid unnecessary slices.
+ if (position > 0 || position + length < contents.length) {
+ if (contents.subarray) {
+ contents = contents.subarray(position, position + length);
+ } else {
+ contents = Array.prototype.slice.call(contents, position, position + length);
+ }
+ }
+ HEAP8.set(contents, ptr);
+ }
+ }
+ return {
+ ptr,
+ allocated
+ };
+ },
+ msync(stream, buffer, offset, length, mmapFlags) {
+ MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
+ // should we check if bytesWritten and length are the same?
+ return 0;
+ }
+ }
+};
+
+/** @param {boolean=} noRunDep */ var asyncLoad = (url, onload, onerror, noRunDep) => {
+ var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : "";
+ readAsync(url).then(arrayBuffer => {
+ onload(new Uint8Array(arrayBuffer));
+ if (dep) removeRunDependency(dep);
+ }, err => {
+ if (onerror) {
+ onerror();
+ } else {
+ throw `Loading data file "${url}" failed.`;
+ }
+ });
+ if (dep) addRunDependency(dep);
+};
+
+var FS_createDataFile = (parent, name, fileData, canRead, canWrite, canOwn) => {
+ FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn);
+};
+
+var preloadPlugins = Module["preloadPlugins"] || [];
+
+var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => {
+ // Ensure plugins are ready.
+ if (typeof Browser != "undefined") Browser.init();
+ var handled = false;
+ preloadPlugins.forEach(plugin => {
+ if (handled) return;
+ if (plugin["canHandle"](fullname)) {
+ plugin["handle"](byteArray, fullname, finish, onerror);
+ handled = true;
+ }
+ });
+ return handled;
+};
+
+var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => {
+ // TODO we should allow people to just pass in a complete filename instead
+ // of parent and name being that we just join them anyways
+ var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent;
+ var dep = getUniqueRunDependency(`cp ${fullname}`);
+ // might have several active requests for the same fullname
+ function processData(byteArray) {
+ function finish(byteArray) {
+ preFinish?.();
+ if (!dontCreateFile) {
+ FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+ }
+ onload?.();
+ removeRunDependency(dep);
+ }
+ if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => {
+ onerror?.();
+ removeRunDependency(dep);
+ })) {
+ return;
+ }
+ finish(byteArray);
+ }
+ addRunDependency(dep);
+ if (typeof url == "string") {
+ asyncLoad(url, processData, onerror);
+ } else {
+ processData(url);
+ }
+};
+
+var FS_modeStringToFlags = str => {
+ var flagModes = {
+ "r": 0,
+ "r+": 2,
+ "w": 512 | 64 | 1,
+ "w+": 512 | 64 | 2,
+ "a": 1024 | 64 | 1,
+ "a+": 1024 | 64 | 2
+ };
+ var flags = flagModes[str];
+ if (typeof flags == "undefined") {
+ throw new Error(`Unknown file open mode: ${str}`);
+ }
+ return flags;
+};
+
+var FS_getMode = (canRead, canWrite) => {
+ var mode = 0;
+ if (canRead) mode |= 292 | 73;
+ if (canWrite) mode |= 146;
+ return mode;
+};
+
+var FS = {
+ root: null,
+ mounts: [],
+ devices: {},
+ streams: [],
+ nextInode: 1,
+ nameTable: null,
+ currentPath: "/",
+ initialized: false,
+ ignorePermissions: true,
+ ErrnoError: class {
+ name="ErrnoError";
+ // We set the `name` property to be able to identify `FS.ErrnoError`
+ // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway.
+ // - when using PROXYFS, an error can come from an underlying FS
+ // as different FS objects have their own FS.ErrnoError each,
+ // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs.
+ // we'll use the reliable test `err.name == "ErrnoError"` instead
+ constructor(errno) {
+ this.errno = errno;
+ }
+ },
+ filesystems: null,
+ syncFSRequests: 0,
+ readFiles: {},
+ FSStream: class {
+ shared={};
+ get object() {
+ return this.node;
+ }
+ set object(val) {
+ this.node = val;
+ }
+ get isRead() {
+ return (this.flags & 2097155) !== 1;
+ }
+ get isWrite() {
+ return (this.flags & 2097155) !== 0;
+ }
+ get isAppend() {
+ return (this.flags & 1024);
+ }
+ get flags() {
+ return this.shared.flags;
+ }
+ set flags(val) {
+ this.shared.flags = val;
+ }
+ get position() {
+ return this.shared.position;
+ }
+ set position(val) {
+ this.shared.position = val;
+ }
+ },
+ FSNode: class {
+ node_ops={};
+ stream_ops={};
+ readMode=292 | 73;
+ writeMode=146;
+ mounted=null;
+ constructor(parent, name, mode, rdev) {
+ if (!parent) {
+ parent = this;
+ }
+ // root node sets parent to itself
+ this.parent = parent;
+ this.mount = parent.mount;
+ this.id = FS.nextInode++;
+ this.name = name;
+ this.mode = mode;
+ this.rdev = rdev;
+ }
+ get read() {
+ return (this.mode & this.readMode) === this.readMode;
+ }
+ set read(val) {
+ val ? this.mode |= this.readMode : this.mode &= ~this.readMode;
+ }
+ get write() {
+ return (this.mode & this.writeMode) === this.writeMode;
+ }
+ set write(val) {
+ val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode;
+ }
+ get isFolder() {
+ return FS.isDir(this.mode);
+ }
+ get isDevice() {
+ return FS.isChrdev(this.mode);
+ }
+ },
+ lookupPath(path, opts = {}) {
+ path = PATH_FS.resolve(path);
+ if (!path) return {
+ path: "",
+ node: null
+ };
+ var defaults = {
+ follow_mount: true,
+ recurse_count: 0
+ };
+ opts = Object.assign(defaults, opts);
+ if (opts.recurse_count > 8) {
+ // max recursive lookup of 8
+ throw new FS.ErrnoError(32);
+ }
+ // split the absolute path
+ var parts = path.split("/").filter(p => !!p);
+ // start at the root
+ var current = FS.root;
+ var current_path = "/";
+ for (var i = 0; i < parts.length; i++) {
+ var islast = (i === parts.length - 1);
+ if (islast && opts.parent) {
+ // stop resolving
+ break;
+ }
+ current = FS.lookupNode(current, parts[i]);
+ current_path = PATH.join2(current_path, parts[i]);
+ // jump to the mount's root node if this is a mountpoint
+ if (FS.isMountpoint(current)) {
+ if (!islast || (islast && opts.follow_mount)) {
+ current = current.mounted.root;
+ }
+ }
+ // by default, lookupPath will not follow a symlink if it is the final path component.
+ // setting opts.follow = true will override this behavior.
+ if (!islast || opts.follow) {
+ var count = 0;
+ while (FS.isLink(current.mode)) {
+ var link = FS.readlink(current_path);
+ current_path = PATH_FS.resolve(PATH.dirname(current_path), link);
+ var lookup = FS.lookupPath(current_path, {
+ recurse_count: opts.recurse_count + 1
+ });
+ current = lookup.node;
+ if (count++ > 40) {
+ // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+ throw new FS.ErrnoError(32);
+ }
+ }
+ }
+ }
+ return {
+ path: current_path,
+ node: current
+ };
+ },
+ getPath(node) {
+ var path;
+ while (true) {
+ if (FS.isRoot(node)) {
+ var mount = node.mount.mountpoint;
+ if (!path) return mount;
+ return mount[mount.length - 1] !== "/" ? `${mount}/${path}` : mount + path;
+ }
+ path = path ? `${node.name}/${path}` : node.name;
+ node = node.parent;
+ }
+ },
+ hashName(parentid, name) {
+ var hash = 0;
+ for (var i = 0; i < name.length; i++) {
+ hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+ }
+ return ((parentid + hash) >>> 0) % FS.nameTable.length;
+ },
+ hashAddNode(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ node.name_next = FS.nameTable[hash];
+ FS.nameTable[hash] = node;
+ },
+ hashRemoveNode(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ if (FS.nameTable[hash] === node) {
+ FS.nameTable[hash] = node.name_next;
+ } else {
+ var current = FS.nameTable[hash];
+ while (current) {
+ if (current.name_next === node) {
+ current.name_next = node.name_next;
+ break;
+ }
+ current = current.name_next;
+ }
+ }
+ },
+ lookupNode(parent, name) {
+ var errCode = FS.mayLookup(parent);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ var hash = FS.hashName(parent.id, name);
+ for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+ var nodeName = node.name;
+ if (node.parent.id === parent.id && nodeName === name) {
+ return node;
+ }
+ }
+ // if we failed to find it in the cache, call into the VFS
+ return FS.lookup(parent, name);
+ },
+ createNode(parent, name, mode, rdev) {
+ var node = new FS.FSNode(parent, name, mode, rdev);
+ FS.hashAddNode(node);
+ return node;
+ },
+ destroyNode(node) {
+ FS.hashRemoveNode(node);
+ },
+ isRoot(node) {
+ return node === node.parent;
+ },
+ isMountpoint(node) {
+ return !!node.mounted;
+ },
+ isFile(mode) {
+ return (mode & 61440) === 32768;
+ },
+ isDir(mode) {
+ return (mode & 61440) === 16384;
+ },
+ isLink(mode) {
+ return (mode & 61440) === 40960;
+ },
+ isChrdev(mode) {
+ return (mode & 61440) === 8192;
+ },
+ isBlkdev(mode) {
+ return (mode & 61440) === 24576;
+ },
+ isFIFO(mode) {
+ return (mode & 61440) === 4096;
+ },
+ isSocket(mode) {
+ return (mode & 49152) === 49152;
+ },
+ flagsToPermissionString(flag) {
+ var perms = [ "r", "w", "rw" ][flag & 3];
+ if ((flag & 512)) {
+ perms += "w";
+ }
+ return perms;
+ },
+ nodePermissions(node, perms) {
+ if (FS.ignorePermissions) {
+ return 0;
+ }
+ // return 0 if any user, group or owner bits are set.
+ if (perms.includes("r") && !(node.mode & 292)) {
+ return 2;
+ } else if (perms.includes("w") && !(node.mode & 146)) {
+ return 2;
+ } else if (perms.includes("x") && !(node.mode & 73)) {
+ return 2;
+ }
+ return 0;
+ },
+ mayLookup(dir) {
+ if (!FS.isDir(dir.mode)) return 54;
+ var errCode = FS.nodePermissions(dir, "x");
+ if (errCode) return errCode;
+ if (!dir.node_ops.lookup) return 2;
+ return 0;
+ },
+ mayCreate(dir, name) {
+ try {
+ var node = FS.lookupNode(dir, name);
+ return 20;
+ } catch (e) {}
+ return FS.nodePermissions(dir, "wx");
+ },
+ mayDelete(dir, name, isdir) {
+ var node;
+ try {
+ node = FS.lookupNode(dir, name);
+ } catch (e) {
+ return e.errno;
+ }
+ var errCode = FS.nodePermissions(dir, "wx");
+ if (errCode) {
+ return errCode;
+ }
+ if (isdir) {
+ if (!FS.isDir(node.mode)) {
+ return 54;
+ }
+ if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+ return 10;
+ }
+ } else {
+ if (FS.isDir(node.mode)) {
+ return 31;
+ }
+ }
+ return 0;
+ },
+ mayOpen(node, flags) {
+ if (!node) {
+ return 44;
+ }
+ if (FS.isLink(node.mode)) {
+ return 32;
+ } else if (FS.isDir(node.mode)) {
+ if (FS.flagsToPermissionString(flags) !== "r" || // opening for write
+ (flags & 512)) {
+ // TODO: check for O_SEARCH? (== search for dir only)
+ return 31;
+ }
+ }
+ return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+ },
+ MAX_OPEN_FDS: 4096,
+ nextfd() {
+ for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) {
+ if (!FS.streams[fd]) {
+ return fd;
+ }
+ }
+ throw new FS.ErrnoError(33);
+ },
+ getStreamChecked(fd) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(8);
+ }
+ return stream;
+ },
+ getStream: fd => FS.streams[fd],
+ createStream(stream, fd = -1) {
+ // clone it, so we can return an instance of FSStream
+ stream = Object.assign(new FS.FSStream, stream);
+ if (fd == -1) {
+ fd = FS.nextfd();
+ }
+ stream.fd = fd;
+ FS.streams[fd] = stream;
+ return stream;
+ },
+ closeStream(fd) {
+ FS.streams[fd] = null;
+ },
+ dupStream(origStream, fd = -1) {
+ var stream = FS.createStream(origStream, fd);
+ stream.stream_ops?.dup?.(stream);
+ return stream;
+ },
+ chrdev_stream_ops: {
+ open(stream) {
+ var device = FS.getDevice(stream.node.rdev);
+ // override node's stream ops with the device's
+ stream.stream_ops = device.stream_ops;
+ // forward the open call
+ stream.stream_ops.open?.(stream);
+ },
+ llseek() {
+ throw new FS.ErrnoError(70);
+ }
+ },
+ major: dev => ((dev) >> 8),
+ minor: dev => ((dev) & 255),
+ makedev: (ma, mi) => ((ma) << 8 | (mi)),
+ registerDevice(dev, ops) {
+ FS.devices[dev] = {
+ stream_ops: ops
+ };
+ },
+ getDevice: dev => FS.devices[dev],
+ getMounts(mount) {
+ var mounts = [];
+ var check = [ mount ];
+ while (check.length) {
+ var m = check.pop();
+ mounts.push(m);
+ check.push(...m.mounts);
+ }
+ return mounts;
+ },
+ syncfs(populate, callback) {
+ if (typeof populate == "function") {
+ callback = populate;
+ populate = false;
+ }
+ FS.syncFSRequests++;
+ if (FS.syncFSRequests > 1) {
+ err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);
+ }
+ var mounts = FS.getMounts(FS.root.mount);
+ var completed = 0;
+ function doCallback(errCode) {
+ FS.syncFSRequests--;
+ return callback(errCode);
+ }
+ function done(errCode) {
+ if (errCode) {
+ if (!done.errored) {
+ done.errored = true;
+ return doCallback(errCode);
+ }
+ return;
+ }
+ if (++completed >= mounts.length) {
+ doCallback(null);
+ }
+ }
+ // sync all mounts
+ mounts.forEach(mount => {
+ if (!mount.type.syncfs) {
+ return done(null);
+ }
+ mount.type.syncfs(mount, populate, done);
+ });
+ },
+ mount(type, opts, mountpoint) {
+ var root = mountpoint === "/";
+ var pseudo = !mountpoint;
+ var node;
+ if (root && FS.root) {
+ throw new FS.ErrnoError(10);
+ } else if (!root && !pseudo) {
+ var lookup = FS.lookupPath(mountpoint, {
+ follow_mount: false
+ });
+ mountpoint = lookup.path;
+ // use the absolute path
+ node = lookup.node;
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ if (!FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ }
+ var mount = {
+ type,
+ opts,
+ mountpoint,
+ mounts: []
+ };
+ // create a root node for the fs
+ var mountRoot = type.mount(mount);
+ mountRoot.mount = mount;
+ mount.root = mountRoot;
+ if (root) {
+ FS.root = mountRoot;
+ } else if (node) {
+ // set as a mountpoint
+ node.mounted = mount;
+ // add the new mount to the current mount's children
+ if (node.mount) {
+ node.mount.mounts.push(mount);
+ }
+ }
+ return mountRoot;
+ },
+ unmount(mountpoint) {
+ var lookup = FS.lookupPath(mountpoint, {
+ follow_mount: false
+ });
+ if (!FS.isMountpoint(lookup.node)) {
+ throw new FS.ErrnoError(28);
+ }
+ // destroy the nodes for this mount, and all its child mounts
+ var node = lookup.node;
+ var mount = node.mounted;
+ var mounts = FS.getMounts(mount);
+ Object.keys(FS.nameTable).forEach(hash => {
+ var current = FS.nameTable[hash];
+ while (current) {
+ var next = current.name_next;
+ if (mounts.includes(current.mount)) {
+ FS.destroyNode(current);
+ }
+ current = next;
+ }
+ });
+ // no longer a mountpoint
+ node.mounted = null;
+ // remove this mount from the child mounts
+ var idx = node.mount.mounts.indexOf(mount);
+ node.mount.mounts.splice(idx, 1);
+ },
+ lookup(parent, name) {
+ return parent.node_ops.lookup(parent, name);
+ },
+ mknod(path, mode, dev) {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ if (!name || name === "." || name === "..") {
+ throw new FS.ErrnoError(28);
+ }
+ var errCode = FS.mayCreate(parent, name);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.mknod) {
+ throw new FS.ErrnoError(63);
+ }
+ return parent.node_ops.mknod(parent, name, mode, dev);
+ },
+ statfs(path) {
+ // NOTE: None of the defaults here are true. We're just returning safe and
+ // sane values.
+ var rtn = {
+ bsize: 4096,
+ frsize: 4096,
+ blocks: 1e6,
+ bfree: 5e5,
+ bavail: 5e5,
+ files: FS.nextInode,
+ ffree: FS.nextInode - 1,
+ fsid: 42,
+ flags: 2,
+ namelen: 255
+ };
+ var parent = FS.lookupPath(path, {
+ follow: true
+ }).node;
+ if (parent?.node_ops.statfs) {
+ Object.assign(rtn, parent.node_ops.statfs(parent.mount.opts.root));
+ }
+ return rtn;
+ },
+ create(path, mode = 438) {
+ mode &= 4095;
+ mode |= 32768;
+ return FS.mknod(path, mode, 0);
+ },
+ mkdir(path, mode = 511) {
+ mode &= 511 | 512;
+ mode |= 16384;
+ return FS.mknod(path, mode, 0);
+ },
+ mkdirTree(path, mode) {
+ var dirs = path.split("/");
+ var d = "";
+ for (var i = 0; i < dirs.length; ++i) {
+ if (!dirs[i]) continue;
+ d += "/" + dirs[i];
+ try {
+ FS.mkdir(d, mode);
+ } catch (e) {
+ if (e.errno != 20) throw e;
+ }
+ }
+ },
+ mkdev(path, mode, dev) {
+ if (typeof dev == "undefined") {
+ dev = mode;
+ mode = 438;
+ }
+ mode |= 8192;
+ return FS.mknod(path, mode, dev);
+ },
+ symlink(oldpath, newpath) {
+ if (!PATH_FS.resolve(oldpath)) {
+ throw new FS.ErrnoError(44);
+ }
+ var lookup = FS.lookupPath(newpath, {
+ parent: true
+ });
+ var parent = lookup.node;
+ if (!parent) {
+ throw new FS.ErrnoError(44);
+ }
+ var newname = PATH.basename(newpath);
+ var errCode = FS.mayCreate(parent, newname);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.symlink) {
+ throw new FS.ErrnoError(63);
+ }
+ return parent.node_ops.symlink(parent, newname, oldpath);
+ },
+ rename(old_path, new_path) {
+ var old_dirname = PATH.dirname(old_path);
+ var new_dirname = PATH.dirname(new_path);
+ var old_name = PATH.basename(old_path);
+ var new_name = PATH.basename(new_path);
+ // parents must exist
+ var lookup, old_dir, new_dir;
+ // let the errors from non existent directories percolate up
+ lookup = FS.lookupPath(old_path, {
+ parent: true
+ });
+ old_dir = lookup.node;
+ lookup = FS.lookupPath(new_path, {
+ parent: true
+ });
+ new_dir = lookup.node;
+ if (!old_dir || !new_dir) throw new FS.ErrnoError(44);
+ // need to be part of the same mount
+ if (old_dir.mount !== new_dir.mount) {
+ throw new FS.ErrnoError(75);
+ }
+ // source must exist
+ var old_node = FS.lookupNode(old_dir, old_name);
+ // old path should not be an ancestor of the new path
+ var relative = PATH_FS.relative(old_path, new_dirname);
+ if (relative.charAt(0) !== ".") {
+ throw new FS.ErrnoError(28);
+ }
+ // new path should not be an ancestor of the old path
+ relative = PATH_FS.relative(new_path, old_dirname);
+ if (relative.charAt(0) !== ".") {
+ throw new FS.ErrnoError(55);
+ }
+ // see if the new path already exists
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {}
+ // early out if nothing needs to change
+ if (old_node === new_node) {
+ return;
+ }
+ // we'll need to delete the old entry
+ var isdir = FS.isDir(old_node.mode);
+ var errCode = FS.mayDelete(old_dir, old_name, isdir);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ // need delete permissions if we'll be overwriting.
+ // need create permissions if new doesn't already exist.
+ errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!old_dir.node_ops.rename) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+ throw new FS.ErrnoError(10);
+ }
+ // if we are going to change the parent, check write permissions
+ if (new_dir !== old_dir) {
+ errCode = FS.nodePermissions(old_dir, "w");
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ }
+ // remove the node from the lookup hash
+ FS.hashRemoveNode(old_node);
+ // do the underlying fs rename
+ try {
+ old_dir.node_ops.rename(old_node, new_dir, new_name);
+ // update old node (we do this here to avoid each backend
+ // needing to)
+ old_node.parent = new_dir;
+ } catch (e) {
+ throw e;
+ } finally {
+ // add the node back to the hash (in case node_ops.rename
+ // changed its name)
+ FS.hashAddNode(old_node);
+ }
+ },
+ rmdir(path) {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var errCode = FS.mayDelete(parent, name, true);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.rmdir) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ parent.node_ops.rmdir(parent, name);
+ FS.destroyNode(node);
+ },
+ readdir(path) {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ var node = lookup.node;
+ if (!node.node_ops.readdir) {
+ throw new FS.ErrnoError(54);
+ }
+ return node.node_ops.readdir(node);
+ },
+ unlink(path) {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ var parent = lookup.node;
+ if (!parent) {
+ throw new FS.ErrnoError(44);
+ }
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var errCode = FS.mayDelete(parent, name, false);
+ if (errCode) {
+ // According to POSIX, we should map EISDIR to EPERM, but
+ // we instead do what Linux does (and we must, as we use
+ // the musl linux libc).
+ throw new FS.ErrnoError(errCode);
+ }
+ if (!parent.node_ops.unlink) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(10);
+ }
+ parent.node_ops.unlink(parent, name);
+ FS.destroyNode(node);
+ },
+ readlink(path) {
+ var lookup = FS.lookupPath(path);
+ var link = lookup.node;
+ if (!link) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!link.node_ops.readlink) {
+ throw new FS.ErrnoError(28);
+ }
+ return link.node_ops.readlink(link);
+ },
+ stat(path, dontFollow) {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontFollow
+ });
+ var node = lookup.node;
+ if (!node) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!node.node_ops.getattr) {
+ throw new FS.ErrnoError(63);
+ }
+ return node.node_ops.getattr(node);
+ },
+ lstat(path) {
+ return FS.stat(path, true);
+ },
+ chmod(path, mode, dontFollow) {
+ var node;
+ if (typeof path == "string") {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontFollow
+ });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ node.node_ops.setattr(node, {
+ mode: (mode & 4095) | (node.mode & ~4095),
+ timestamp: Date.now()
+ });
+ },
+ lchmod(path, mode) {
+ FS.chmod(path, mode, true);
+ },
+ fchmod(fd, mode) {
+ var stream = FS.getStreamChecked(fd);
+ FS.chmod(stream.node, mode);
+ },
+ chown(path, uid, gid, dontFollow) {
+ var node;
+ if (typeof path == "string") {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontFollow
+ });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ node.node_ops.setattr(node, {
+ timestamp: Date.now()
+ });
+ },
+ // we ignore the uid / gid for now
+ lchown(path, uid, gid) {
+ FS.chown(path, uid, gid, true);
+ },
+ fchown(fd, uid, gid) {
+ var stream = FS.getStreamChecked(fd);
+ FS.chown(stream.node, uid, gid);
+ },
+ truncate(path, len) {
+ if (len < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ var node;
+ if (typeof path == "string") {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(63);
+ }
+ if (FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!FS.isFile(node.mode)) {
+ throw new FS.ErrnoError(28);
+ }
+ var errCode = FS.nodePermissions(node, "w");
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ node.node_ops.setattr(node, {
+ size: len,
+ timestamp: Date.now()
+ });
+ },
+ ftruncate(fd, len) {
+ var stream = FS.getStreamChecked(fd);
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(28);
+ }
+ FS.truncate(stream.node, len);
+ },
+ utime(path, atime, mtime) {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ var node = lookup.node;
+ node.node_ops.setattr(node, {
+ timestamp: Math.max(atime, mtime)
+ });
+ },
+ open(path, flags, mode = 438) {
+ if (path === "") {
+ throw new FS.ErrnoError(44);
+ }
+ flags = typeof flags == "string" ? FS_modeStringToFlags(flags) : flags;
+ if ((flags & 64)) {
+ mode = (mode & 4095) | 32768;
+ } else {
+ mode = 0;
+ }
+ var node;
+ if (typeof path == "object") {
+ node = path;
+ } else {
+ path = PATH.normalize(path);
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & 131072)
+ });
+ node = lookup.node;
+ } catch (e) {}
+ }
+ // perhaps we need to create the node
+ var created = false;
+ if ((flags & 64)) {
+ if (node) {
+ // if O_CREAT and O_EXCL are set, error out if the node already exists
+ if ((flags & 128)) {
+ throw new FS.ErrnoError(20);
+ }
+ } else {
+ // node doesn't exist, try to create it
+ node = FS.mknod(path, mode, 0);
+ created = true;
+ }
+ }
+ if (!node) {
+ throw new FS.ErrnoError(44);
+ }
+ // can't truncate a device
+ if (FS.isChrdev(node.mode)) {
+ flags &= ~512;
+ }
+ // if asked only for a directory, then this must be one
+ if ((flags & 65536) && !FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ // check permissions, if this is not a file we just created now (it is ok to
+ // create and write to a file with read-only permissions; it is read-only
+ // for later use)
+ if (!created) {
+ var errCode = FS.mayOpen(node, flags);
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ }
+ // do truncation if necessary
+ if ((flags & 512) && !created) {
+ FS.truncate(node, 0);
+ }
+ // we've already handled these, don't pass down to the underlying vfs
+ flags &= ~(128 | 512 | 131072);
+ // register the stream with the filesystem
+ var stream = FS.createStream({
+ node,
+ path: FS.getPath(node),
+ // we want the absolute path to the node
+ flags,
+ seekable: true,
+ position: 0,
+ stream_ops: node.stream_ops,
+ // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+ ungotten: [],
+ error: false
+ });
+ // call the new stream's open function
+ if (stream.stream_ops.open) {
+ stream.stream_ops.open(stream);
+ }
+ if (Module["logReadFiles"] && !(flags & 1)) {
+ if (!(path in FS.readFiles)) {
+ FS.readFiles[path] = 1;
+ }
+ }
+ return stream;
+ },
+ close(stream) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (stream.getdents) stream.getdents = null;
+ // free readdir state
+ try {
+ if (stream.stream_ops.close) {
+ stream.stream_ops.close(stream);
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ FS.closeStream(stream.fd);
+ }
+ stream.fd = null;
+ },
+ isClosed(stream) {
+ return stream.fd === null;
+ },
+ llseek(stream, offset, whence) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (!stream.seekable || !stream.stream_ops.llseek) {
+ throw new FS.ErrnoError(70);
+ }
+ if (whence != 0 && whence != 1 && whence != 2) {
+ throw new FS.ErrnoError(28);
+ }
+ stream.position = stream.stream_ops.llseek(stream, offset, whence);
+ stream.ungotten = [];
+ return stream.position;
+ },
+ read(stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if ((stream.flags & 2097155) === 1) {
+ throw new FS.ErrnoError(8);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!stream.stream_ops.read) {
+ throw new FS.ErrnoError(28);
+ }
+ var seeking = typeof position != "undefined";
+ if (!seeking) {
+ position = stream.position;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(70);
+ }
+ var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesRead;
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, position, canOwn) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(8);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(31);
+ }
+ if (!stream.stream_ops.write) {
+ throw new FS.ErrnoError(28);
+ }
+ if (stream.seekable && stream.flags & 1024) {
+ // seek to the end before writing in append mode
+ FS.llseek(stream, 0, 2);
+ }
+ var seeking = typeof position != "undefined";
+ if (!seeking) {
+ position = stream.position;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(70);
+ }
+ var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+ if (!seeking) stream.position += bytesWritten;
+ return bytesWritten;
+ },
+ allocate(stream, offset, length) {
+ if (FS.isClosed(stream)) {
+ throw new FS.ErrnoError(8);
+ }
+ if (offset < 0 || length <= 0) {
+ throw new FS.ErrnoError(28);
+ }
+ if ((stream.flags & 2097155) === 0) {
+ throw new FS.ErrnoError(8);
+ }
+ if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ if (!stream.stream_ops.allocate) {
+ throw new FS.ErrnoError(138);
+ }
+ stream.stream_ops.allocate(stream, offset, length);
+ },
+ mmap(stream, length, position, prot, flags) {
+ // User requests writing to file (prot & PROT_WRITE != 0).
+ // Checking if we have permissions to write to the file unless
+ // MAP_PRIVATE flag is set. According to POSIX spec it is possible
+ // to write to file opened in read-only mode with MAP_PRIVATE flag,
+ // as all modifications will be visible only in the memory of
+ // the current process.
+ if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) {
+ throw new FS.ErrnoError(2);
+ }
+ if ((stream.flags & 2097155) === 1) {
+ throw new FS.ErrnoError(2);
+ }
+ if (!stream.stream_ops.mmap) {
+ throw new FS.ErrnoError(43);
+ }
+ if (!length) {
+ throw new FS.ErrnoError(28);
+ }
+ return stream.stream_ops.mmap(stream, length, position, prot, flags);
+ },
+ msync(stream, buffer, offset, length, mmapFlags) {
+ if (!stream.stream_ops.msync) {
+ return 0;
+ }
+ return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);
+ },
+ ioctl(stream, cmd, arg) {
+ if (!stream.stream_ops.ioctl) {
+ throw new FS.ErrnoError(59);
+ }
+ return stream.stream_ops.ioctl(stream, cmd, arg);
+ },
+ readFile(path, opts = {}) {
+ opts.flags = opts.flags || 0;
+ opts.encoding = opts.encoding || "binary";
+ if (opts.encoding !== "utf8" && opts.encoding !== "binary") {
+ throw new Error(`Invalid encoding type "${opts.encoding}"`);
+ }
+ var ret;
+ var stream = FS.open(path, opts.flags);
+ var stat = FS.stat(path);
+ var length = stat.size;
+ var buf = new Uint8Array(length);
+ FS.read(stream, buf, 0, length, 0);
+ if (opts.encoding === "utf8") {
+ ret = UTF8ArrayToString(buf);
+ } else if (opts.encoding === "binary") {
+ ret = buf;
+ }
+ FS.close(stream);
+ return ret;
+ },
+ writeFile(path, data, opts = {}) {
+ opts.flags = opts.flags || 577;
+ var stream = FS.open(path, opts.flags, opts.mode);
+ if (typeof data == "string") {
+ var buf = new Uint8Array(lengthBytesUTF8(data) + 1);
+ var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);
+ FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn);
+ } else if (ArrayBuffer.isView(data)) {
+ FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
+ } else {
+ throw new Error("Unsupported data type");
+ }
+ FS.close(stream);
+ },
+ cwd: () => FS.currentPath,
+ chdir(path) {
+ var lookup = FS.lookupPath(path, {
+ follow: true
+ });
+ if (lookup.node === null) {
+ throw new FS.ErrnoError(44);
+ }
+ if (!FS.isDir(lookup.node.mode)) {
+ throw new FS.ErrnoError(54);
+ }
+ var errCode = FS.nodePermissions(lookup.node, "x");
+ if (errCode) {
+ throw new FS.ErrnoError(errCode);
+ }
+ FS.currentPath = lookup.path;
+ },
+ createDefaultDirectories() {
+ FS.mkdir("/tmp");
+ FS.mkdir("/home");
+ FS.mkdir("/home/web_user");
+ },
+ createDefaultDevices() {
+ // create /dev
+ FS.mkdir("/dev");
+ // setup /dev/null
+ FS.registerDevice(FS.makedev(1, 3), {
+ read: () => 0,
+ write: (stream, buffer, offset, length, pos) => length,
+ llseek: () => 0
+ });
+ FS.mkdev("/dev/null", FS.makedev(1, 3));
+ // setup /dev/tty and /dev/tty1
+ // stderr needs to print output using err() rather than out()
+ // so we register a second tty just for it.
+ TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+ TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+ FS.mkdev("/dev/tty", FS.makedev(5, 0));
+ FS.mkdev("/dev/tty1", FS.makedev(6, 0));
+ // setup /dev/[u]random
+ // use a buffer to avoid overhead of individual crypto calls per byte
+ var randomBuffer = new Uint8Array(1024), randomLeft = 0;
+ var randomByte = () => {
+ if (randomLeft === 0) {
+ randomLeft = randomFill(randomBuffer).byteLength;
+ }
+ return randomBuffer[--randomLeft];
+ };
+ FS.createDevice("/dev", "random", randomByte);
+ FS.createDevice("/dev", "urandom", randomByte);
+ // we're not going to emulate the actual shm device,
+ // just create the tmp dirs that reside in it commonly
+ FS.mkdir("/dev/shm");
+ FS.mkdir("/dev/shm/tmp");
+ },
+ createSpecialDirectories() {
+ // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the
+ // name of the stream for fd 6 (see test_unistd_ttyname)
+ FS.mkdir("/proc");
+ var proc_self = FS.mkdir("/proc/self");
+ FS.mkdir("/proc/self/fd");
+ FS.mount({
+ mount() {
+ var node = FS.createNode(proc_self, "fd", 16895, 73);
+ node.node_ops = {
+ lookup(parent, name) {
+ var fd = +name;
+ var stream = FS.getStreamChecked(fd);
+ var ret = {
+ parent: null,
+ mount: {
+ mountpoint: "fake"
+ },
+ node_ops: {
+ readlink: () => stream.path
+ }
+ };
+ ret.parent = ret;
+ // make it look like a simple root node
+ return ret;
+ }
+ };
+ return node;
+ }
+ }, {}, "/proc/self/fd");
+ },
+ createStandardStreams(input, output, error) {
+ // TODO deprecate the old functionality of a single
+ // input / output callback and that utilizes FS.createDevice
+ // and instead require a unique set of stream ops
+ // by default, we symlink the standard streams to the
+ // default tty devices. however, if the standard streams
+ // have been overwritten we create a unique device for
+ // them instead.
+ if (input) {
+ FS.createDevice("/dev", "stdin", input);
+ } else {
+ FS.symlink("/dev/tty", "/dev/stdin");
+ }
+ if (output) {
+ FS.createDevice("/dev", "stdout", null, output);
+ } else {
+ FS.symlink("/dev/tty", "/dev/stdout");
+ }
+ if (error) {
+ FS.createDevice("/dev", "stderr", null, error);
+ } else {
+ FS.symlink("/dev/tty1", "/dev/stderr");
+ }
+ // open default streams for the stdin, stdout and stderr devices
+ var stdin = FS.open("/dev/stdin", 0);
+ var stdout = FS.open("/dev/stdout", 1);
+ var stderr = FS.open("/dev/stderr", 1);
+ },
+ staticInit() {
+ FS.nameTable = new Array(4096);
+ FS.mount(MEMFS, {}, "/");
+ FS.createDefaultDirectories();
+ FS.createDefaultDevices();
+ FS.createSpecialDirectories();
+ FS.filesystems = {
+ "MEMFS": MEMFS
+ };
+ },
+ init(input, output, error) {
+ FS.initialized = true;
+ // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+ input ??= Module["stdin"];
+ output ??= Module["stdout"];
+ error ??= Module["stderr"];
+ FS.createStandardStreams(input, output, error);
+ },
+ quit() {
+ FS.initialized = false;
+ // force-flush all streams, so we get musl std streams printed out
+ // close all of our streams
+ for (var i = 0; i < FS.streams.length; i++) {
+ var stream = FS.streams[i];
+ if (!stream) {
+ continue;
+ }
+ FS.close(stream);
+ }
+ },
+ findObject(path, dontResolveLastLink) {
+ var ret = FS.analyzePath(path, dontResolveLastLink);
+ if (!ret.exists) {
+ return null;
+ }
+ return ret.object;
+ },
+ analyzePath(path, dontResolveLastLink) {
+ // operate from within the context of the symlink's target
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !dontResolveLastLink
+ });
+ path = lookup.path;
+ } catch (e) {}
+ var ret = {
+ isRoot: false,
+ exists: false,
+ error: 0,
+ name: null,
+ path: null,
+ object: null,
+ parentExists: false,
+ parentPath: null,
+ parentObject: null
+ };
+ try {
+ var lookup = FS.lookupPath(path, {
+ parent: true
+ });
+ ret.parentExists = true;
+ ret.parentPath = lookup.path;
+ ret.parentObject = lookup.node;
+ ret.name = PATH.basename(path);
+ lookup = FS.lookupPath(path, {
+ follow: !dontResolveLastLink
+ });
+ ret.exists = true;
+ ret.path = lookup.path;
+ ret.object = lookup.node;
+ ret.name = lookup.node.name;
+ ret.isRoot = lookup.path === "/";
+ } catch (e) {
+ ret.error = e.errno;
+ }
+ return ret;
+ },
+ createPath(parent, path, canRead, canWrite) {
+ parent = typeof parent == "string" ? parent : FS.getPath(parent);
+ var parts = path.split("/").reverse();
+ while (parts.length) {
+ var part = parts.pop();
+ if (!part) continue;
+ var current = PATH.join2(parent, part);
+ try {
+ FS.mkdir(current);
+ } catch (e) {}
+ // ignore EEXIST
+ parent = current;
+ }
+ return current;
+ },
+ createFile(parent, name, properties, canRead, canWrite) {
+ var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
+ var mode = FS_getMode(canRead, canWrite);
+ return FS.create(path, mode);
+ },
+ createDataFile(parent, name, data, canRead, canWrite, canOwn) {
+ var path = name;
+ if (parent) {
+ parent = typeof parent == "string" ? parent : FS.getPath(parent);
+ path = name ? PATH.join2(parent, name) : parent;
+ }
+ var mode = FS_getMode(canRead, canWrite);
+ var node = FS.create(path, mode);
+ if (data) {
+ if (typeof data == "string") {
+ var arr = new Array(data.length);
+ for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+ data = arr;
+ }
+ // make sure we can write to the file
+ FS.chmod(node, mode | 146);
+ var stream = FS.open(node, 577);
+ FS.write(stream, data, 0, data.length, 0, canOwn);
+ FS.close(stream);
+ FS.chmod(node, mode);
+ }
+ },
+ createDevice(parent, name, input, output) {
+ var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
+ var mode = FS_getMode(!!input, !!output);
+ FS.createDevice.major ??= 64;
+ var dev = FS.makedev(FS.createDevice.major++, 0);
+ // Create a fake device that a set of stream ops to emulate
+ // the old behavior.
+ FS.registerDevice(dev, {
+ open(stream) {
+ stream.seekable = false;
+ },
+ close(stream) {
+ // flush any pending line data
+ if (output?.buffer?.length) {
+ output(10);
+ }
+ },
+ read(stream, buffer, offset, length, pos) {
+ /* ignored */ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = input();
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(6);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset + i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write(stream, buffer, offset, length, pos) {
+ for (var i = 0; i < length; i++) {
+ try {
+ output(buffer[offset + i]);
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ });
+ return FS.mkdev(path, mode, dev);
+ },
+ forceLoadFile(obj) {
+ if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+ if (typeof XMLHttpRequest != "undefined") {
+ throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+ } else {
+ // Command-line.
+ try {
+ obj.contents = readBinary(obj.url);
+ obj.usedBytes = obj.contents.length;
+ } catch (e) {
+ throw new FS.ErrnoError(29);
+ }
+ }
+ },
+ createLazyFile(parent, name, url, canRead, canWrite) {
+ // Lazy chunked Uint8Array (implements get and length from Uint8Array).
+ // Actual getting is abstracted away for eventual reuse.
+ class LazyUint8Array {
+ lengthKnown=false;
+ chunks=[];
+ // Loaded chunks. Index is the chunk number
+ get(idx) {
+ if (idx > this.length - 1 || idx < 0) {
+ return undefined;
+ }
+ var chunkOffset = idx % this.chunkSize;
+ var chunkNum = (idx / this.chunkSize) | 0;
+ return this.getter(chunkNum)[chunkOffset];
+ }
+ setDataGetter(getter) {
+ this.getter = getter;
+ }
+ cacheLength() {
+ // Find length
+ var xhr = new XMLHttpRequest;
+ xhr.open("HEAD", url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+ var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
+ var chunkSize = 1024 * 1024;
+ // Chunk size in bytes
+ if (!hasByteServing) chunkSize = datalength;
+ // Function to get a range from the remote URL.
+ var doXHR = (from, to) => {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength - 1) throw new Error("only " + datalength + " bytes available! programmer error!");
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+ // Some hints to the browser that we want binary data.
+ xhr.responseType = "arraybuffer";
+ if (xhr.overrideMimeType) {
+ xhr.overrideMimeType("text/plain; charset=x-user-defined");
+ }
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ if (xhr.response !== undefined) {
+ return new Uint8Array(/** @type{Array<number>} */ (xhr.response || []));
+ }
+ return intArrayFromString(xhr.responseText || "", true);
+ };
+ var lazyArray = this;
+ lazyArray.setDataGetter(chunkNum => {
+ var start = chunkNum * chunkSize;
+ var end = (chunkNum + 1) * chunkSize - 1;
+ // including this byte
+ end = Math.min(end, datalength - 1);
+ // if datalength-1 is selected, this is the last block
+ if (typeof lazyArray.chunks[chunkNum] == "undefined") {
+ lazyArray.chunks[chunkNum] = doXHR(start, end);
+ }
+ if (typeof lazyArray.chunks[chunkNum] == "undefined") throw new Error("doXHR failed!");
+ return lazyArray.chunks[chunkNum];
+ });
+ if (usesGzip || !datalength) {
+ // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length
+ chunkSize = datalength = 1;
+ // this will force getter(0)/doXHR do download the whole file
+ datalength = this.getter(0).length;
+ chunkSize = datalength;
+ out("LazyFiles on gzip forces download of the whole file when length is accessed");
+ }
+ this._length = datalength;
+ this._chunkSize = chunkSize;
+ this.lengthKnown = true;
+ }
+ get length() {
+ if (!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._length;
+ }
+ get chunkSize() {
+ if (!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._chunkSize;
+ }
+ }
+ if (typeof XMLHttpRequest != "undefined") {
+ if (!ENVIRONMENT_IS_WORKER) throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";
+ var lazyArray = new LazyUint8Array;
+ var properties = {
+ isDevice: false,
+ contents: lazyArray
+ };
+ } else {
+ var properties = {
+ isDevice: false,
+ url
+ };
+ }
+ var node = FS.createFile(parent, name, properties, canRead, canWrite);
+ // This is a total hack, but I want to get this lazy file code out of the
+ // core of MEMFS. If we want to keep this lazy file concept I feel it should
+ // be its own thin LAZYFS proxying calls to MEMFS.
+ if (properties.contents) {
+ node.contents = properties.contents;
+ } else if (properties.url) {
+ node.contents = null;
+ node.url = properties.url;
+ }
+ // Add a function that defers querying the file size until it is asked the first time.
+ Object.defineProperties(node, {
+ usedBytes: {
+ get: function() {
+ return this.contents.length;
+ }
+ }
+ });
+ // override each stream op with one that tries to force load the lazy file first
+ var stream_ops = {};
+ var keys = Object.keys(node.stream_ops);
+ keys.forEach(key => {
+ var fn = node.stream_ops[key];
+ stream_ops[key] = (...args) => {
+ FS.forceLoadFile(node);
+ return fn(...args);
+ };
+ });
+ function writeChunks(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ if (position >= contents.length) return 0;
+ var size = Math.min(contents.length - position, length);
+ if (contents.slice) {
+ // normal array
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ } else {
+ for (var i = 0; i < size; i++) {
+ // LazyUint8Array from sync binary XHR
+ buffer[offset + i] = contents.get(position + i);
+ }
+ }
+ return size;
+ }
+ // use a custom read function
+ stream_ops.read = (stream, buffer, offset, length, position) => {
+ FS.forceLoadFile(node);
+ return writeChunks(stream, buffer, offset, length, position);
+ };
+ // use a custom mmap function
+ stream_ops.mmap = (stream, length, position, prot, flags) => {
+ FS.forceLoadFile(node);
+ var ptr = mmapAlloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(48);
+ }
+ writeChunks(stream, HEAP8, ptr, length, position);
+ return {
+ ptr,
+ allocated: true
+ };
+ };
+ node.stream_ops = stream_ops;
+ return node;
+ }
+};
+
+/**
+ * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the
+ * emscripten HEAP, returns a copy of that string as a Javascript String object.
+ *
+ * @param {number} ptr
+ * @param {number=} maxBytesToRead - An optional length that specifies the
+ * maximum number of bytes to read. You can omit this parameter to scan the
+ * string until the first 0 byte. If maxBytesToRead is passed, and the string
+ * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the
+ * string will cut short at that byte index (i.e. maxBytesToRead will not
+ * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing
+ * frequent uses of UTF8ToString() with and without maxBytesToRead may throw
+ * JS JIT optimizations off, so it is worth to consider consistently using one
+ * @return {string}
+ */ var UTF8ToString = (ptr, maxBytesToRead) => ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : "";
+
+var SYSCALLS = {
+ DEFAULT_POLLMASK: 5,
+ calculateAt(dirfd, path, allowEmpty) {
+ if (PATH.isAbs(path)) {
+ return path;
+ }
+ // relative path
+ var dir;
+ if (dirfd === -100) {
+ dir = FS.cwd();
+ } else {
+ var dirstream = SYSCALLS.getStreamFromFD(dirfd);
+ dir = dirstream.path;
+ }
+ if (path.length == 0) {
+ if (!allowEmpty) {
+ throw new FS.ErrnoError(44);
+ }
+ return dir;
+ }
+ return PATH.join2(dir, path);
+ },
+ doStat(func, path, buf) {
+ var stat = func(path);
+ HEAP32[((buf) >> 2)] = stat.dev;
+ HEAP32[(((buf) + (4)) >> 2)] = stat.mode;
+ HEAPU32[(((buf) + (8)) >> 2)] = stat.nlink;
+ HEAP32[(((buf) + (12)) >> 2)] = stat.uid;
+ HEAP32[(((buf) + (16)) >> 2)] = stat.gid;
+ HEAP32[(((buf) + (20)) >> 2)] = stat.rdev;
+ (tempI64 = [ stat.size >>> 0, (tempDouble = stat.size, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (24)) >> 2)] = tempI64[0], HEAP32[(((buf) + (28)) >> 2)] = tempI64[1]);
+ HEAP32[(((buf) + (32)) >> 2)] = 4096;
+ HEAP32[(((buf) + (36)) >> 2)] = stat.blocks;
+ var atime = stat.atime.getTime();
+ var mtime = stat.mtime.getTime();
+ var ctime = stat.ctime.getTime();
+ (tempI64 = [ Math.floor(atime / 1e3) >>> 0, (tempDouble = Math.floor(atime / 1e3),
+ (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (40)) >> 2)] = tempI64[0], HEAP32[(((buf) + (44)) >> 2)] = tempI64[1]);
+ HEAPU32[(((buf) + (48)) >> 2)] = (atime % 1e3) * 1e3 * 1e3;
+ (tempI64 = [ Math.floor(mtime / 1e3) >>> 0, (tempDouble = Math.floor(mtime / 1e3),
+ (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (56)) >> 2)] = tempI64[0], HEAP32[(((buf) + (60)) >> 2)] = tempI64[1]);
+ HEAPU32[(((buf) + (64)) >> 2)] = (mtime % 1e3) * 1e3 * 1e3;
+ (tempI64 = [ Math.floor(ctime / 1e3) >>> 0, (tempDouble = Math.floor(ctime / 1e3),
+ (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (72)) >> 2)] = tempI64[0], HEAP32[(((buf) + (76)) >> 2)] = tempI64[1]);
+ HEAPU32[(((buf) + (80)) >> 2)] = (ctime % 1e3) * 1e3 * 1e3;
+ (tempI64 = [ stat.ino >>> 0, (tempDouble = stat.ino, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[(((buf) + (88)) >> 2)] = tempI64[0], HEAP32[(((buf) + (92)) >> 2)] = tempI64[1]);
+ return 0;
+ },
+ doMsync(addr, stream, len, flags, offset) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(43);
+ }
+ if (flags & 2) {
+ // MAP_PRIVATE calls need not to be synced back to underlying fs
+ return 0;
+ }
+ var buffer = HEAPU8.slice(addr, addr + len);
+ FS.msync(stream, buffer, offset, len, flags);
+ },
+ getStreamFromFD(fd) {
+ var stream = FS.getStreamChecked(fd);
+ return stream;
+ },
+ varargs: undefined,
+ getStr(ptr) {
+ var ret = UTF8ToString(ptr);
+ return ret;
+ }
+};
+
+function _fd_close(fd) {
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ FS.close(stream);
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+/** @param {number=} offset */ var doReadv = (stream, iov, iovcnt, offset) => {
+ var ret = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[((iov) >> 2)];
+ var len = HEAPU32[(((iov) + (4)) >> 2)];
+ iov += 8;
+ var curr = FS.read(stream, HEAP8, ptr, len, offset);
+ if (curr < 0) return -1;
+ ret += curr;
+ if (curr < len) break;
+ // nothing more to read
+ if (typeof offset != "undefined") {
+ offset += curr;
+ }
+ }
+ return ret;
+};
+
+function _fd_read(fd, iov, iovcnt, pnum) {
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var num = doReadv(stream, iov, iovcnt);
+ HEAPU32[((pnum) >> 2)] = num;
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+var convertI32PairToI53Checked = (lo, hi) => ((hi + 2097152) >>> 0 < 4194305 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN;
+
+function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
+ var offset = convertI32PairToI53Checked(offset_low, offset_high);
+ try {
+ if (isNaN(offset)) return 61;
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ FS.llseek(stream, offset, whence);
+ (tempI64 = [ stream.position >>> 0, (tempDouble = stream.position, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ],
+ HEAP32[((newOffset) >> 2)] = tempI64[0], HEAP32[(((newOffset) + (4)) >> 2)] = tempI64[1]);
+ if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null;
+ // reset readdir state
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+/** @param {number=} offset */ var doWritev = (stream, iov, iovcnt, offset) => {
+ var ret = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[((iov) >> 2)];
+ var len = HEAPU32[(((iov) + (4)) >> 2)];
+ iov += 8;
+ var curr = FS.write(stream, HEAP8, ptr, len, offset);
+ if (curr < 0) return -1;
+ ret += curr;
+ if (curr < len) {
+ // No more space to write.
+ break;
+ }
+ if (typeof offset != "undefined") {
+ offset += curr;
+ }
+ }
+ return ret;
+};
+
+function _fd_write(fd, iov, iovcnt, pnum) {
+ try {
+ var stream = SYSCALLS.getStreamFromFD(fd);
+ var num = doWritev(stream, iov, iovcnt);
+ HEAPU32[((pnum) >> 2)] = num;
+ return 0;
+ } catch (e) {
+ if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
+ return e.errno;
+ }
+}
+
+var runtimeKeepaliveCounter = 0;
+
+var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
+
+var _proc_exit = code => {
+ EXITSTATUS = code;
+ if (!keepRuntimeAlive()) {
+ Module["onExit"]?.(code);
+ ABORT = true;
+ }
+ quit_(code, new ExitStatus(code));
+};
+
+/** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => {
+ EXITSTATUS = status;
+ _proc_exit(status);
+};
+
+var handleException = e => {
+ // Certain exception types we do not treat as errors since they are used for
+ // internal control flow.
+ // 1. ExitStatus, which is thrown by exit()
+ // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others
+ // that wish to return to JS event loop.
+ if (e instanceof ExitStatus || e == "unwind") {
+ return EXITSTATUS;
+ }
+ quit_(1, e);
+};
+
+var stackAlloc = sz => __emscripten_stack_alloc(sz);
+
+var stringToUTF8OnStack = str => {
+ var size = lengthBytesUTF8(str) + 1;
+ var ret = stackAlloc(size);
+ stringToUTF8(str, ret, size);
+ return ret;
+};
+
+FS.createPreloadedFile = FS_createPreloadedFile;
+
+FS.staticInit();
+
+// This error may happen quite a bit. To avoid overhead we reuse it (and
+// suffer a lack of stack info).
+MEMFS.doesNotExistError = new FS.ErrnoError(44);
+
+/** @suppress {checkTypes} */ MEMFS.doesNotExistError.stack = "<generic error, no stack>";
+
+var wasmImports = {
+ /** @export */ __cxa_throw: ___cxa_throw,
+ /** @export */ _abort_js: __abort_js,
+ /** @export */ _emscripten_memcpy_js: __emscripten_memcpy_js,
+ /** @export */ _tzset_js: __tzset_js,
+ /** @export */ emscripten_date_now: _emscripten_date_now,
+ /** @export */ emscripten_resize_heap: _emscripten_resize_heap,
+ /** @export */ environ_get: _environ_get,
+ /** @export */ environ_sizes_get: _environ_sizes_get,
+ /** @export */ fd_close: _fd_close,
+ /** @export */ fd_read: _fd_read,
+ /** @export */ fd_seek: _fd_seek,
+ /** @export */ fd_write: _fd_write
+};
+
+var wasmExports = createWasm();
+
+var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["__wasm_call_ctors"])();
+
+var _main = Module["_main"] = (a0, a1) => (_main = Module["_main"] = wasmExports["__main_argc_argv"])(a0, a1);
+
+var __emscripten_stack_restore = a0 => (__emscripten_stack_restore = wasmExports["_emscripten_stack_restore"])(a0);
+
+var __emscripten_stack_alloc = a0 => (__emscripten_stack_alloc = wasmExports["_emscripten_stack_alloc"])(a0);
+
+var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports["emscripten_stack_get_current"])();
+
+var dynCall_viijii = Module["dynCall_viijii"] = (a0, a1, a2, a3, a4, a5, a6) => (dynCall_viijii = Module["dynCall_viijii"] = wasmExports["dynCall_viijii"])(a0, a1, a2, a3, a4, a5, a6);
+
+var dynCall_jiji = Module["dynCall_jiji"] = (a0, a1, a2, a3, a4) => (dynCall_jiji = Module["dynCall_jiji"] = wasmExports["dynCall_jiji"])(a0, a1, a2, a3, a4);
+
+var dynCall_iiiiij = Module["dynCall_iiiiij"] = (a0, a1, a2, a3, a4, a5, a6) => (dynCall_iiiiij = Module["dynCall_iiiiij"] = wasmExports["dynCall_iiiiij"])(a0, a1, a2, a3, a4, a5, a6);
+
+var dynCall_iiiiijj = Module["dynCall_iiiiijj"] = (a0, a1, a2, a3, a4, a5, a6, a7, a8) => (dynCall_iiiiijj = Module["dynCall_iiiiijj"] = wasmExports["dynCall_iiiiijj"])(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+var dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) => (dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = wasmExports["dynCall_iiiiiijj"])(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+// include: postamble.js
+// === Auto-generated postamble setup entry stuff ===
+var calledRun;
+
+dependenciesFulfilled = function runCaller() {
+ // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+ if (!calledRun) run();
+ if (!calledRun) dependenciesFulfilled = runCaller;
+};
+
+// try this again later, after new deps are fulfilled
+function callMain(args = []) {
+ var entryFunction = _main;
+ args.unshift(thisProgram);
+ var argc = args.length;
+ var argv = stackAlloc((argc + 1) * 4);
+ var argv_ptr = argv;
+ args.forEach(arg => {
+ HEAPU32[((argv_ptr) >> 2)] = stringToUTF8OnStack(arg);
+ argv_ptr += 4;
+ });
+ HEAPU32[((argv_ptr) >> 2)] = 0;
+ try {
+ var ret = entryFunction(argc, argv);
+ // if we're not running an evented main loop, it's time to exit
+ exitJS(ret, /* implicit = */ true);
+ return ret;
+ } catch (e) {
+ return handleException(e);
+ }
+}
+
+function run(args = arguments_) {
+ if (runDependencies > 0) {
+ return;
+ }
+ preRun();
+ // a preRun added a dependency, run will be called later
+ if (runDependencies > 0) {
+ return;
+ }
+ function doRun() {
+ // run may have just been called through dependencies being fulfilled just in this very frame,
+ // or while the async setStatus time below was happening
+ if (calledRun) return;
+ calledRun = true;
+ Module["calledRun"] = true;
+ if (ABORT) return;
+ initRuntime();
+ preMain();
+ readyPromiseResolve(Module);
+ Module["onRuntimeInitialized"]?.();
+ if (shouldRunNow) callMain(args);
+ postRun();
+ }
+ if (Module["setStatus"]) {
+ Module["setStatus"]("Running...");
+ setTimeout(() => {
+ setTimeout(() => Module["setStatus"](""), 1);
+ doRun();
+ }, 1);
+ } else {
+ doRun();
+ }
+}
+
+if (Module["preInit"]) {
+ if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ];
+ while (Module["preInit"].length > 0) {
+ Module["preInit"].pop()();
+ }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+
+if (Module["noInitialRun"]) shouldRunNow = false;
+
+run();
+
+// end include: postamble.js
+// include: postamble_modularize.js
+// In MODULARIZE mode we wrap the generated code in a factory function
+// and return either the Module itself, or a promise of the module.
+// We assign to the `moduleRtn` global here and configure closure to see
+// this as and extern so it won't get minified.
+moduleRtn = readyPromise;
+
+
+ return moduleRtn;
+}
+);
+})();
+if (typeof exports === 'object' && typeof module === 'object')
+ module.exports = setupModule;
+else if (typeof define === 'function' && define['amd'])
+ define([], () => setupModule);
diff --git a/wasm/gcc-loops/build/gcc-loops.js.symbols b/wasm/gcc-loops/build/gcc-loops.js.symbols
new file mode 100644
index 0000000..8a5dab9
--- /dev/null
+++ b/wasm/gcc-loops/build/gcc-loops.js.symbols
@@ -0,0 +1,653 @@
+0:__cxa_throw
+1:_emscripten_memcpy_js
+2:emscripten_date_now
+3:emscripten_resize_heap
+4:__wasi_fd_write
+5:__wasi_fd_read
+6:__wasi_fd_close
+7:_abort_js
+8:__wasi_environ_sizes_get
+9:__wasi_environ_get
+10:_tzset_js
+11:legalimport$__wasi_fd_seek
+12:__wasm_call_ctors
+13:example1\28\29
+14:example2a\28int\2c\20int\29
+15:example2b\28int\2c\20int\29
+16:example3\28int\2c\20int*\2c\20int*\29
+17:example4a\28int\2c\20int*\2c\20int*\29
+18:example4b\28int\2c\20int*\2c\20int*\29
+19:example4c\28int\2c\20int*\2c\20int*\29
+20:example7\28int\29
+21:example8\28int\29
+22:example9\28unsigned\20int*\29
+23:example10a\28short*\2c\20short*\2c\20short*\2c\20int*\2c\20int*\2c\20int*\29
+24:example10b\28short*\2c\20short*\2c\20short*\2c\20int*\2c\20int*\2c\20int*\29
+25:example11\28\29
+26:example12\28\29
+27:example21\28int*\2c\20int\29
+28:example23\28unsigned\20short*\2c\20unsigned\20int*\29
+29:example24\28short\2c\20short\29
+30:example25\28\29
+31:main
+32:Timer::~Timer\28\29
+33:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\20std::__2::__put_character_sequence\5babi:ne180100\5d<char\2c\20std::__2::char_traits<char>>\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20char\20const*\2c\20unsigned\20long\29
+34:std::__2::vector<unsigned\20int\2c\20std::__2::allocator<unsigned\20int>>::__throw_length_error\5babi:ne180100\5d\28\29\20const
+35:std::__2::__throw_length_error\5babi:ne180100\5d\28char\20const*\29
+36:__memcpy
+37:__memset
+38:__gettimeofday
+39:strlen
+40:sbrk
+41:emscripten_builtin_malloc
+42:emscripten_builtin_free
+43:dlrealloc
+44:dispose_chunk
+45:__wasi_syscall_ret
+46:__stdio_seek
+47:__stdio_write
+48:__stdio_read
+49:dummy
+50:__stdio_close
+51:__pthread_mutex_lock
+52:__lock
+53:__lockfile
+54:fflush
+55:memmove
+56:__toread
+57:abort
+58:__towrite
+59:__fwritex
+60:fwrite
+61:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::~basic_ios\28\29
+62:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::~basic_ios\28\29_84
+63:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::~basic_streambuf\28\29
+64:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::~basic_streambuf\28\29_86
+65:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::basic_streambuf\28\29
+66:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::imbue\28std::__2::locale\20const&\29
+67:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::setbuf\28char*\2c\20long\29
+68:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29
+69:std::__2::fpos<__mbstate_t>::fpos\5babi:nn180100\5d\28long\20long\29
+70:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29
+71:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::xsgetn\28char*\2c\20long\29
+72:long\20const&\20std::__2::min\5babi:nn180100\5d<long>\28long\20const&\2c\20long\20const&\29
+73:std::__2::char_traits<char>::copy\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29
+74:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::underflow\28\29
+75:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::uflow\28\29
+76:std::__2::char_traits<char>::to_int_type\5babi:nn180100\5d\28char\29
+77:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::pbackfail\28int\29
+78:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::xsputn\28char\20const*\2c\20long\29
+79:std::__2::basic_istream<char\2c\20std::__2::char_traits<char>>::~basic_istream\28\29_110
+80:virtual\20thunk\20to\20std::__2::basic_istream<char\2c\20std::__2::char_traits<char>>::~basic_istream\28\29
+81:std::__2::basic_istream<char\2c\20std::__2::char_traits<char>>::~basic_istream\28\29_112
+82:virtual\20thunk\20to\20std::__2::basic_istream<char\2c\20std::__2::char_traits<char>>::~basic_istream\28\29_113
+83:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::good\5babi:nn180100\5d\28\29\20const
+84:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::flush\28\29
+85:std::__2::ctype<char>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::ctype<char>>\28std::__2::locale\20const&\29
+86:bool\20std::__2::operator==\5babi:nn180100\5d<char\2c\20std::__2::char_traits<char>>\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\20const&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\20const&\29
+87:std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>::operator*\5babi:nn180100\5d\28\29\20const
+88:std::__2::ctype<char>::is\5babi:nn180100\5d\28unsigned\20long\2c\20char\29\20const
+89:std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>::operator++\5babi:nn180100\5d\28\29
+90:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::setstate\5babi:nn180100\5d\28unsigned\20int\29
+91:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::pubsync\5babi:nn180100\5d\28\29
+92:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::sgetc\5babi:nn180100\5d\28\29
+93:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::sbumpc\5babi:nn180100\5d\28\29
+94:std::__2::char_traits<char>::eq_int_type\5babi:nn180100\5d\28int\2c\20int\29
+95:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::~basic_ostream\28\29_138
+96:virtual\20thunk\20to\20std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::~basic_ostream\28\29
+97:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::~basic_ostream\28\29_140
+98:virtual\20thunk\20to\20std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::~basic_ostream\28\29_141
+99:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::sentry::sentry\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\29
+100:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::sentry::~sentry\28\29
+101:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>>\28std::__2::locale\20const&\29
+102:std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>::ostreambuf_iterator\5babi:nn180100\5d\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\29
+103:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::fill\5babi:nn180100\5d\28\29\20const
+104:std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>::failed\5babi:nn180100\5d\28\29\20const
+105:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::put\5babi:nn180100\5d\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20long\29\20const
+106:std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>::operator=\5babi:nn180100\5d\28char\29
+107:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::sputn\5babi:nn180100\5d\28char\20const*\2c\20long\29
+108:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::~basic_streambuf\28\29
+109:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::~basic_streambuf\28\29_161
+110:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::basic_streambuf\28\29
+111:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::xsgetn\28wchar_t*\2c\20long\29
+112:std::__2::char_traits<wchar_t>::copy\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20unsigned\20long\29
+113:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::uflow\28\29
+114:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::xsputn\28wchar_t\20const*\2c\20long\29
+115:std::__2::basic_ostream<wchar_t\2c\20std::__2::char_traits<wchar_t>>::flush\28\29
+116:std::__2::ctype<wchar_t>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::ctype<wchar_t>>\28std::__2::locale\20const&\29
+117:bool\20std::__2::operator==\5babi:nn180100\5d<wchar_t\2c\20std::__2::char_traits<wchar_t>>\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\20const&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\20const&\29
+118:std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>::operator*\5babi:nn180100\5d\28\29\20const
+119:std::__2::ctype<wchar_t>::is\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29\20const
+120:std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>::operator++\5babi:nn180100\5d\28\29
+121:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::sgetc\5babi:nn180100\5d\28\29
+122:std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>::sbumpc\5babi:nn180100\5d\28\29
+123:std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>::operator=\5babi:nn180100\5d\28wchar_t\29
+124:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::basic_string\5babi:nn180100\5d\28\29
+125:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::operator=\5babi:nn180100\5d\28std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>&&\29
+126:std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>::getloc\5babi:nn180100\5d\28\29\20const
+127:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__get_pointer\5babi:nn180100\5d\28\29
+128:std::__2::enable_if<is_move_constructible<unsigned\20int>::value\20&&\20is_move_assignable<unsigned\20int>::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d<unsigned\20int>\28unsigned\20int&\2c\20unsigned\20int&\29
+129:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__is_long\5babi:nn180100\5d\28\29\20const
+130:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__get_short_size\5babi:nn180100\5d\28\29\20const
+131:void\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__init<char*\2c\200>\28char*\2c\20char*\29
+132:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::size\5babi:nn180100\5d\28\29\20const
+133:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::capacity\5babi:nn180100\5d\28\29\20const
+134:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::resize\5babi:nn180100\5d\28unsigned\20long\29
+135:std::__2::char_traits<char>::not_eof\5babi:nn180100\5d\28int\29
+136:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__get_long_cap\5babi:nn180100\5d\28\29\20const
+137:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>>\28std::__2::locale\20const&\29
+138:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>::always_noconv\5babi:nn180100\5d\28\29\20const
+139:unsigned\20long\20const&\20std::__2::min\5babi:nn180100\5d<unsigned\20long>\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29
+140:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>::in\5babi:nn180100\5d\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+141:std::__2::__throw_bad_cast\5babi:nn180100\5d\28\29
+142:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>::out\5babi:nn180100\5d\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+143:bool\20std::__2::__less<void\2c\20void>::operator\28\29\5babi:nn180100\5d<long\2c\20long>\28long\20const&\2c\20long\20const&\29\20const
+144:auto\20std::__2::__unwrap_range\5babi:nn180100\5d<char\20const*\2c\20char\20const*>\28char\20const*\2c\20char\20const*\29
+145:std::__2::pair<char\20const*\2c\20char*>\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d<char\20const\2c\20char\2c\200>\28char\20const*\2c\20char\20const*\2c\20char*\29\20const
+146:char\20const*\20std::__2::__rewrap_range\5babi:nn180100\5d<char\20const*\2c\20char\20const*\2c\20char\20const*>\28char\20const*\2c\20char\20const*\29
+147:char*\20std::__2::__rewrap_iter\5babi:nn180100\5d<char*\2c\20char*\2c\20std::__2::__unwrap_iter_impl<char*\2c\20true>>\28char*\2c\20char*\29
+148:std::__2::pair<std::__2::__unwrap_ref_decay<char\20const*>::type\2c\20std::__2::__unwrap_ref_decay<char*>::type>\20std::__2::make_pair\5babi:nn180100\5d<char\20const*\2c\20char*>\28char\20const*&&\2c\20char*&&\29
+149:std::__2::pair<char\20const*\2c\20char*>::pair\5babi:nn180100\5d<char\20const*\2c\20char*\2c\200>\28char\20const*&&\2c\20char*&&\29
+150:char*\20std::__2::__constexpr_memmove\5babi:nn180100\5d<char\2c\20char\20const\2c\200>\28char*\2c\20char\20const*\2c\20std::__2::__element_count\29
+151:std::__2::pair<wchar_t\20const*\2c\20wchar_t*>\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d<wchar_t\20const\2c\20wchar_t\2c\200>\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t*\29\20const
+152:wchar_t*\20std::__2::__constexpr_memmove\5babi:nn180100\5d<wchar_t\2c\20wchar_t\20const\2c\200>\28wchar_t*\2c\20wchar_t\20const*\2c\20std::__2::__element_count\29
+153:std::__2::allocator_traits<std::__2::allocator<char>>::deallocate\5babi:nn180100\5d\28std::__2::allocator<char>&\2c\20char*\2c\20unsigned\20long\29
+154:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__set_short_size\5babi:nn180100\5d\28unsigned\20long\29
+155:std::__2::char_traits<char>::assign\5babi:nn180100\5d\28char&\2c\20char\20const&\29
+156:std::__2::__libcpp_deallocate\5babi:nn180100\5d\28void*\2c\20unsigned\20long\2c\20unsigned\20long\29
+157:std::__2::__is_overaligned_for_new\5babi:nn180100\5d\28unsigned\20long\29
+158:std::__2::iterator_traits<char*>::difference_type\20std::__2::distance\5babi:nn180100\5d<char*>\28char*\2c\20char*\29
+159:std::__2::iterator_traits<char*>::difference_type\20std::__2::__distance\5babi:nn180100\5d<char*>\28char*\2c\20char*\2c\20std::__2::random_access_iterator_tag\29
+160:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29
+161:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__recommend\5babi:nn180100\5d\28unsigned\20long\29
+162:std::__2::__allocation_result<std::__2::allocator_traits<std::__2::allocator<char>>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d<std::__2::allocator<char>>\28std::__2::allocator<char>&\2c\20unsigned\20long\29
+163:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__set_long_pointer\5babi:nn180100\5d\28char*\29
+164:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__set_long_cap\5babi:nn180100\5d\28unsigned\20long\29
+165:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__set_long_size\5babi:nn180100\5d\28unsigned\20long\29
+166:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__throw_length_error\5babi:nn180100\5d\28\29\20const
+167:std::__2::__libcpp_allocate\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\29
+168:bool\20std::__2::__less<void\2c\20void>::operator\28\29\5babi:nn180100\5d<unsigned\20long\2c\20unsigned\20long>\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29\20const
+169:std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>::__test_for_eof\5babi:nn180100\5d\28\29\20const
+170:std::__2::ctype<char>::widen\5babi:nn180100\5d\28char\29\20const
+171:std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>::__test_for_eof\5babi:nn180100\5d\28\29\20const
+172:std::__2::ctype<wchar_t>::widen\5babi:nn180100\5d\28char\29\20const
+173:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::basic_string\5babi:nn180100\5d<0>\28char\20const*\29
+174:std::__2::ios_base::getloc\28\29\20const
+175:unsigned\20long\20const&\20std::__2::max\5babi:nn180100\5d<unsigned\20long>\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29
+176:std::__2::ios_base::clear\28unsigned\20int\29
+177:std::__2::ios_base::~ios_base\28\29
+178:std::__2::ios_base::~ios_base\28\29_372
+179:std::__2::__compressed_pair_elem<void\20\28*\29\28void*\29\2c\201\2c\20false>::__compressed_pair_elem\5babi:nn180100\5d<void\20\28*\29\28void*\29\2c\20void>\28void\20\28*&&\29\28void*\29\29
+180:__emscripten_stdout_seek
+181:ungetc
+182:__uflow
+183:getc
+184:fwide
+185:mbtowc
+186:mbrtowc
+187:__fgetwc_unlocked
+188:wcrtomb
+189:wctomb
+190:__fputwc_unlocked
+191:std::__2::__stdoutbuf<char>::__stdoutbuf\28_IO_FILE*\2c\20__mbstate_t*\29
+192:std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>::basic_ostream\5babi:nn180100\5d\28std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>*\29
+193:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::tie\5babi:nn180100\5d\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>*\29
+194:std::__2::__stdoutbuf<wchar_t>::__stdoutbuf\28_IO_FILE*\2c\20__mbstate_t*\29
+195:std::__2::basic_ostream<wchar_t\2c\20std::__2::char_traits<wchar_t>>::basic_ostream\5babi:nn180100\5d\28std::__2::basic_streambuf<wchar_t\2c\20std::__2::char_traits<wchar_t>>*\29
+196:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::basic_ios\5babi:nn180100\5d\28\29
+197:std::__2::basic_ios<char\2c\20std::__2::char_traits<char>>::init\5babi:nn180100\5d\28std::__2::basic_streambuf<char\2c\20std::__2::char_traits<char>>*\29
+198:std::__2::ios_base::setf\5babi:nn180100\5d\28unsigned\20int\29
+199:std::__2::basic_ios<wchar_t\2c\20std::__2::char_traits<wchar_t>>::basic_ios\5babi:nn180100\5d\28\29
+200:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>>\28std::__2::locale\20const&\29
+201:__cxx_global_array_dtor.1
+202:std::__2::__stdinbuf<char>::~__stdinbuf\28\29
+203:std::__2::__stdinbuf<char>::imbue\28std::__2::locale\20const&\29
+204:std::__2::__stdinbuf<char>::underflow\28\29
+205:std::__2::__stdinbuf<char>::__getchar\28bool\29
+206:std::__2::__stdinbuf<char>::uflow\28\29
+207:std::__2::__stdinbuf<char>::pbackfail\28int\29
+208:std::__2::__do_ungetc\28int\2c\20_IO_FILE*\2c\20char\29
+209:int\20const&\20std::__2::max\5babi:nn180100\5d<int>\28int\20const&\2c\20int\20const&\29
+210:std::__2::ios_base::ios_base\5babi:nn180100\5d\28\29
+211:std::__2::__stdoutbuf<char>::imbue\28std::__2::locale\20const&\29
+212:std::__2::__stdoutbuf<char>::sync\28\29
+213:std::__2::__stdoutbuf<char>::xsputn\28char\20const*\2c\20long\29
+214:std::__2::__stdoutbuf<char>::overflow\28int\29
+215:std::__2::__stdinbuf<wchar_t>::~__stdinbuf\28\29
+216:std::__2::__stdinbuf<wchar_t>::imbue\28std::__2::locale\20const&\29
+217:std::__2::__stdinbuf<wchar_t>::underflow\28\29
+218:std::__2::__stdinbuf<wchar_t>::__getchar\28bool\29
+219:std::__2::__stdinbuf<wchar_t>::uflow\28\29
+220:std::__2::__stdinbuf<wchar_t>::pbackfail\28int\29
+221:std::__2::__do_ungetc\28int\2c\20_IO_FILE*\2c\20wchar_t\29
+222:std::__2::__stdoutbuf<wchar_t>::imbue\28std::__2::locale\20const&\29
+223:std::__2::__stdoutbuf<wchar_t>::xsputn\28wchar_t\20const*\2c\20long\29
+224:std::__2::__stdoutbuf<wchar_t>::overflow\28int\29
+225:__shlim
+226:__shgetc
+227:__ashlti3
+228:__floatsitf
+229:__lshrti3
+230:__multf3
+231:__addtf3
+232:__extenddftf2
+233:__letf2
+234:__getf2
+235:scalbn
+236:copysignl
+237:__floatunsitf
+238:__subtf3
+239:scalbnl
+240:__multi3
+241:__divtf3
+242:fmodl
+243:__floatscan
+244:__isspace
+245:scanexp
+246:__trunctfsf2
+247:__trunctfdf2
+248:store_int
+249:memchr
+250:vsscanf
+251:string_read
+252:getenv
+253:strcmp
+254:__get_locale
+255:memcmp
+256:__loc_is_allocated
+257:toupper
+258:tolower
+259:frexp
+260:printf_core
+261:out
+262:getint
+263:pop_arg
+264:fmt_u
+265:pad
+266:fmt_fp
+267:pop_arg_long_double
+268:vsnprintf
+269:sn_write
+270:__isxdigit_l
+271:__isdigit_l
+272:snprintf
+273:__nl_langinfo_l
+274:strtox
+275:week_num
+276:__strftime_l
+277:is_leap
+278:sscanf
+279:freelocale
+280:mbsrtowcs
+281:__uselocale
+282:strtox_577
+283:std::__2::collate<char>::~collate\28\29_585
+284:std::__2::collate<char>::do_compare\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const
+285:std::__2::collate<char>::do_transform\28char\20const*\2c\20char\20const*\29\20const
+286:std::__2::collate<char>::do_hash\28char\20const*\2c\20char\20const*\29\20const
+287:std::__2::collate<wchar_t>::do_compare\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const
+288:std::__2::collate<wchar_t>::do_transform\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const
+289:void\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::__init<wchar_t\20const*\2c\200>\28wchar_t\20const*\2c\20wchar_t\20const*\29
+290:std::__2::collate<wchar_t>::do_hash\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const
+291:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const
+292:std::__2::locale::~locale\28\29
+293:std::__2::numpunct<char>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::numpunct<char>>\28std::__2::locale\20const&\29
+294:std::__2::numpunct<char>::truename\5babi:nn180100\5d\28\29\20const
+295:std::__2::numpunct<char>::falsename\5babi:nn180100\5d\28\29\20const
+296:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d<std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*\2c\20std::__2::ctype<char>>\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*\2c\20std::__2::ctype<char>\20const&\2c\20unsigned\20int&\2c\20bool\29
+297:std::__2::locale::use_facet\28std::__2::locale::id&\29\20const
+298:std::__2::iterator_traits<std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*>::difference_type\20std::__2::distance\5babi:nn180100\5d<std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*>\28std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const*\29
+299:std::__2::unique_ptr<unsigned\20char\2c\20void\20\28*\29\28void*\29>::unique_ptr\5babi:nn180100\5d<true\2c\20void>\28unsigned\20char*\2c\20std::__2::__dependent_type<std::__2::__unique_ptr_deleter_sfinae<void\20\28*\29\28void*\29>\2c\20true>::__good_rval_ref_type\29
+300:std::__2::unique_ptr<unsigned\20char\2c\20void\20\28*\29\28void*\29>::reset\5babi:nn180100\5d\28unsigned\20char*\29
+301:std::__2::ctype<char>::toupper\5babi:nn180100\5d\28char\29\20const
+302:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const
+303:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::empty\5babi:nn180100\5d\28\29\20const
+304:std::__2::unique_ptr<unsigned\20char\2c\20void\20\28*\29\28void*\29>::~unique_ptr\5babi:nn180100\5d\28\29
+305:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const
+306:std::__2::__num_get_base::__get_base\28std::__2::ios_base&\29
+307:std::__2::__num_get<char>::__stage2_int_prep\28std::__2::ios_base&\2c\20char&\29
+308:std::__2::__num_get<char>::__stage2_int_loop\28char\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20char\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20char\20const*\29
+309:long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d<long>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29
+310:std::__2::__check_grouping\28std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int&\29
+311:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const
+312:long\20long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d<long\20long>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29
+313:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const
+314:unsigned\20short\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d<unsigned\20short>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29
+315:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const
+316:unsigned\20int\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d<unsigned\20int>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29
+317:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const
+318:unsigned\20long\20long\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d<unsigned\20long\20long>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29
+319:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const
+320:std::__2::__num_get<char>::__stage2_float_prep\28std::__2::ios_base&\2c\20char*\2c\20char&\2c\20char&\29
+321:std::__2::__num_get<char>::__stage2_float_loop\28char\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20char\2c\20char\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20char*\29
+322:float\20std::__2::__num_get_float\5babi:nn180100\5d<float>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29
+323:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const
+324:double\20std::__2::__num_get_float\5babi:nn180100\5d<double>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29
+325:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const
+326:long\20double\20std::__2::__num_get_float\5babi:nn180100\5d<long\20double>\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29
+327:std::__2::num_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const
+328:std::__2::ctype<char>::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const
+329:std::__2::__cloc\28\29
+330:std::__2::__libcpp_sscanf_l\28char\20const*\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29
+331:char\20const*\20std::__2::find\5babi:nn180100\5d<char\20const*\2c\20char>\28char\20const*\2c\20char\20const*\2c\20char\20const&\29
+332:std::__2::__libcpp_locale_guard::__libcpp_locale_guard\5babi:nn180100\5d\28__locale_struct*&\29
+333:std::__2::__libcpp_locale_guard::~__libcpp_locale_guard\5babi:nn180100\5d\28\29
+334:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const
+335:std::__2::numpunct<wchar_t>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::numpunct<wchar_t>>\28std::__2::locale\20const&\29
+336:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d<std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const*\2c\20std::__2::ctype<wchar_t>>\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const*\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const*\2c\20std::__2::ctype<wchar_t>\20const&\2c\20unsigned\20int&\2c\20bool\29
+337:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const
+338:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const
+339:std::__2::__num_get<wchar_t>::__do_widen\28std::__2::ios_base&\2c\20wchar_t*\29\20const
+340:std::__2::__num_get<wchar_t>::__stage2_int_prep\28std::__2::ios_base&\2c\20wchar_t&\29
+341:std::__2::__num_get<wchar_t>::__stage2_int_loop\28wchar_t\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20wchar_t\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20wchar_t\20const*\29
+342:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const
+343:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const
+344:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const
+345:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const
+346:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const
+347:std::__2::__num_get<wchar_t>::__stage2_float_prep\28std::__2::ios_base&\2c\20wchar_t*\2c\20wchar_t&\2c\20wchar_t&\29
+348:std::__2::__num_get<wchar_t>::__stage2_float_loop\28wchar_t\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20wchar_t*\29
+349:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const
+350:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const
+351:std::__2::num_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const
+352:std::__2::ctype<wchar_t>::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const
+353:wchar_t\20const*\20std::__2::find\5babi:nn180100\5d<wchar_t\20const*\2c\20wchar_t>\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const&\29
+354:std::__2::numpunct<char>::decimal_point\5babi:nn180100\5d\28\29\20const
+355:std::__2::numpunct<char>::thousands_sep\5babi:nn180100\5d\28\29\20const
+356:std::__2::numpunct<char>::grouping\5babi:nn180100\5d\28\29\20const
+357:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20bool\29\20const
+358:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::begin\5babi:nn180100\5d\28\29
+359:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::end\5babi:nn180100\5d\28\29
+360:bool\20std::__2::operator!=\5babi:nn180100\5d<char*>\28std::__2::__wrap_iter<char*>\20const&\2c\20std::__2::__wrap_iter<char*>\20const&\29
+361:std::__2::__wrap_iter<char*>::operator++\5babi:nn180100\5d\28\29
+362:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__make_iterator\5babi:nn180100\5d\28char*\29
+363:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20long\29\20const
+364:std::__2::__num_put_base::__format_int\28char*\2c\20char\20const*\2c\20bool\2c\20unsigned\20int\29
+365:std::__2::__libcpp_snprintf_l\28char*\2c\20unsigned\20long\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29
+366:std::__2::__num_put_base::__identify_padding\28char*\2c\20char*\2c\20std::__2::ios_base\20const&\29
+367:std::__2::__num_put<char>::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29
+368:std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\20std::__2::__pad_and_output\5babi:nn180100\5d<char\2c\20std::__2::char_traits<char>>\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ios_base&\2c\20char\29
+369:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20long\29\20const
+370:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\29\20const
+371:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\20long\29\20const
+372:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20double\29\20const
+373:std::__2::__num_put_base::__format_float\28char*\2c\20char\20const*\2c\20unsigned\20int\29
+374:std::__2::ios_base::precision\5babi:nn180100\5d\28\29\20const
+375:std::__2::__libcpp_asprintf_l\28char**\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29
+376:std::__2::__num_put<char>::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29
+377:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const
+378:std::__2::num_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20void\20const*\29\20const
+379:std::__2::ios_base::width\5babi:nn180100\5d\28\29\20const
+380:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20char\29
+381:std::__2::ios_base::width\5babi:nn180100\5d\28long\29
+382:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20bool\29\20const
+383:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::end\5babi:nn180100\5d\28\29
+384:std::__2::__wrap_iter<wchar_t*>::operator++\5babi:nn180100\5d\28\29
+385:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\29\20const
+386:std::__2::__num_put<wchar_t>::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29
+387:std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\20std::__2::__pad_and_output\5babi:nn180100\5d<wchar_t\2c\20std::__2::char_traits<wchar_t>>\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ios_base&\2c\20wchar_t\29
+388:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20long\29\20const
+389:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\29\20const
+390:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\20long\29\20const
+391:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20double\29\20const
+392:std::__2::__num_put<wchar_t>::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29
+393:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const
+394:std::__2::num_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20void\20const*\29\20const
+395:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29
+396:void\20std::__2::reverse\5babi:nn180100\5d<char*>\28char*\2c\20char*\29
+397:void\20std::__2::reverse\5babi:nn180100\5d<wchar_t*>\28wchar_t*\2c\20wchar_t*\29
+398:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\20const*\2c\20char\20const*\29\20const
+399:std::__2::ctype<char>::narrow\5babi:nn180100\5d\28char\2c\20char\29\20const
+400:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_date_order\28\29\20const
+401:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get_time\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+402:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get_date\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+403:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get_weekday\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+404:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20unsigned\20int&\2c\20std::__2::ctype<char>\20const&\29\20const
+405:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get_monthname\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+406:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20unsigned\20int&\2c\20std::__2::ctype<char>\20const&\29\20const
+407:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get_year\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+408:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20unsigned\20int&\2c\20std::__2::ctype<char>\20const&\29\20const
+409:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20unsigned\20int&\2c\20std::__2::ctype<char>\20const&\2c\20int\29
+410:std::__2::time_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const
+411:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const
+412:std::__2::ctype<wchar_t>::narrow\5babi:nn180100\5d\28wchar_t\2c\20char\29\20const
+413:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get_time\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+414:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get_date\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+415:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get_weekday\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+416:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20unsigned\20int&\2c\20std::__2::ctype<wchar_t>\20const&\29\20const
+417:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get_monthname\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+418:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20unsigned\20int&\2c\20std::__2::ctype<wchar_t>\20const&\29\20const
+419:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get_year\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const
+420:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20unsigned\20int&\2c\20std::__2::ctype<wchar_t>\20const&\29\20const
+421:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20unsigned\20int&\2c\20std::__2::ctype<wchar_t>\20const&\2c\20int\29
+422:std::__2::time_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const
+423:std::__2::time_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::ios_base&\2c\20char\2c\20tm\20const*\2c\20char\2c\20char\29\20const
+424:std::__2::__time_put::__do_put\28char*\2c\20char*&\2c\20tm\20const*\2c\20char\2c\20char\29\20const
+425:std::__2::enable_if<is_move_constructible<char>::value\20&&\20is_move_assignable<char>::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d<char>\28char&\2c\20char&\29
+426:std::__2::time_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20tm\20const*\2c\20char\2c\20char\29\20const
+427:unsigned\20long\20std::__2::\28anonymous\20namespace\29::countof<wchar_t>\28wchar_t\20const*\2c\20wchar_t\20const*\29
+428:std::__2::moneypunct<char\2c\20false>::do_decimal_point\28\29\20const
+429:std::__2::moneypunct<char\2c\20false>::do_grouping\28\29\20const
+430:std::__2::moneypunct<char\2c\20false>::do_negative_sign\28\29\20const
+431:std::__2::moneypunct<char\2c\20false>::do_pos_format\28\29\20const
+432:std::__2::moneypunct<wchar_t\2c\20false>::do_decimal_point\28\29\20const
+433:std::__2::moneypunct<wchar_t\2c\20false>::do_negative_sign\28\29\20const
+434:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::basic_string\28std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\29
+435:std::__2::money_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const
+436:std::__2::money_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::__do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>&\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype<char>\20const&\2c\20std::__2::unique_ptr<char\2c\20void\20\28*\29\28void*\29>&\2c\20char*&\2c\20char*\29
+437:std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>::operator++\5babi:nn180100\5d\28int\29
+438:void\20std::__2::__double_or_nothing\5babi:nn180100\5d<char>\28std::__2::unique_ptr<char\2c\20void\20\28*\29\28void*\29>&\2c\20char*&\2c\20char*&\29
+439:void\20std::__2::__double_or_nothing\5babi:nn180100\5d<unsigned\20int>\28std::__2::unique_ptr<unsigned\20int\2c\20void\20\28*\29\28void*\29>&\2c\20unsigned\20int*&\2c\20unsigned\20int*&\29
+440:std::__2::__compressed_pair<char*\2c\20void\20\28*\29\28void*\29>::second\5babi:nn180100\5d\28\29
+441:std::__2::money_get<char\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_get\28std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20std::__2::istreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>&\29\20const
+442:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29
+443:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__set_size\5babi:nn180100\5d\28unsigned\20long\29
+444:std::__2::moneypunct<char\2c\20true>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::moneypunct<char\2c\20true>>\28std::__2::locale\20const&\29
+445:std::__2::moneypunct<char\2c\20true>::neg_format\5babi:nn180100\5d\28\29\20const
+446:std::__2::moneypunct<char\2c\20true>::negative_sign\5babi:nn180100\5d\28\29\20const
+447:std::__2::moneypunct<char\2c\20true>::frac_digits\5babi:nn180100\5d\28\29\20const
+448:std::__2::moneypunct<char\2c\20false>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::moneypunct<char\2c\20false>>\28std::__2::locale\20const&\29
+449:std::__2::__wrap_iter<char*>::operator+\5babi:nn180100\5d\28long\29\20const
+450:std::__2::unique_ptr<char\2c\20void\20\28*\29\28void*\29>::release\5babi:nn180100\5d\28\29
+451:std::__2::unique_ptr<char\2c\20void\20\28*\29\28void*\29>::operator=\5babi:nn180100\5d\28std::__2::unique_ptr<char\2c\20void\20\28*\29\28void*\29>&&\29
+452:std::__2::money_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const
+453:std::__2::money_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::__do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>&\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype<wchar_t>\20const&\2c\20std::__2::unique_ptr<wchar_t\2c\20void\20\28*\29\28void*\29>&\2c\20wchar_t*&\2c\20wchar_t*\29
+454:std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>::operator++\5babi:nn180100\5d\28int\29
+455:std::__2::money_get<wchar_t\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_get\28std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20std::__2::istreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>&\29\20const
+456:std::__2::char_traits<wchar_t>::assign\5babi:nn180100\5d\28wchar_t&\2c\20wchar_t\20const&\29
+457:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::capacity\5babi:nn180100\5d\28\29\20const
+458:std::__2::iterator_traits<wchar_t*>::difference_type\20std::__2::distance\5babi:nn180100\5d<wchar_t*>\28wchar_t*\2c\20wchar_t*\29
+459:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29
+460:std::__2::moneypunct<wchar_t\2c\20true>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::moneypunct<wchar_t\2c\20true>>\28std::__2::locale\20const&\29
+461:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::operator=\5babi:nn180100\5d\28std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>&&\29
+462:std::__2::moneypunct<wchar_t\2c\20false>\20const&\20std::__2::use_facet\5babi:nn180100\5d<std::__2::moneypunct<wchar_t\2c\20false>>\28std::__2::locale\20const&\29
+463:std::__2::__wrap_iter<wchar_t*>::operator+\5babi:nn180100\5d\28long\29\20const
+464:std::__2::money_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const
+465:std::__2::__money_put<char>::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20char&\2c\20char&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>&\2c\20int&\29
+466:std::__2::__money_put<char>::__format\28char*\2c\20char*&\2c\20char*&\2c\20unsigned\20int\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ctype<char>\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20char\2c\20char\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20int\29
+467:std::__2::moneypunct<char\2c\20true>::pos_format\5babi:nn180100\5d\28\29\20const
+468:char*\20std::__2::copy\5babi:nn180100\5d<std::__2::__wrap_iter<char\20const*>\2c\20char*>\28std::__2::__wrap_iter<char\20const*>\2c\20std::__2::__wrap_iter<char\20const*>\2c\20char*\29
+469:std::__2::money_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::do_put\28std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\29\20const
+470:std::__2::money_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const
+471:std::__2::__money_put<wchar_t>::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20wchar_t&\2c\20wchar_t&\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>&\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>&\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>&\2c\20int&\29
+472:std::__2::__money_put<wchar_t>::__format\28wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20unsigned\20int\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ctype<wchar_t>\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const&\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const&\2c\20int\29
+473:wchar_t*\20std::__2::copy\5babi:nn180100\5d<std::__2::__wrap_iter<wchar_t\20const*>\2c\20wchar_t*>\28std::__2::__wrap_iter<wchar_t\20const*>\2c\20std::__2::__wrap_iter<wchar_t\20const*>\2c\20wchar_t*\29
+474:std::__2::money_put<wchar_t\2c\20std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>>::do_put\28std::__2::ostreambuf_iterator<wchar_t\2c\20std::__2::char_traits<wchar_t>>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const&\29\20const
+475:std::__2::messages<char>::do_open\28std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\2c\20std::__2::locale\20const&\29\20const
+476:std::__2::messages<char>::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>\20const&\29\20const
+477:std::__2::messages<wchar_t>::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>\20const&\29\20const
+478:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::~codecvt\28\29
+479:std::__2::locale::facet::facet\5babi:nn180100\5d\28unsigned\20long\29
+480:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::__destroy_vector::__destroy_vector\5babi:nn180100\5d\28std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>&\29
+481:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::__construct_at_end\28unsigned\20long\29
+482:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::size\5babi:nn180100\5d\28\29\20const
+483:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::__clear\5babi:nn180100\5d\28\29
+484:std::__2::locale::id::__get\28\29
+485:std::__2::locale::__imp::install\28std::__2::locale::facet*\2c\20long\29
+486:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29
+487:std::__2::__shared_count::__add_shared\5babi:nn180100\5d\28\29
+488:std::__2::__shared_count::__release_shared\5babi:nn180100\5d\28\29
+489:std::__2::locale::__imp::~__imp\28\29
+490:long\20std::__2::__libcpp_atomic_refcount_decrement\5babi:nn180100\5d<long>\28long&\29
+491:std::__2::locale::__imp::~__imp\28\29_1190
+492:std::__2::locale::locale\28std::__2::locale\20const&\29
+493:std::__2::locale::__imp::acquire\28\29
+494:std::__2::locale::locale\28\29
+495:std::__2::locale::facet::__on_zero_shared\28\29
+496:void\20std::__2::__call_once_proxy\5babi:nn180100\5d<std::__2::tuple<std::__2::locale::id::__get\28\29::$_0&&>>\28void*\29
+497:std::__2::ctype<wchar_t>::do_is\28unsigned\20long\2c\20wchar_t\29\20const
+498:std::__2::ctype<wchar_t>::do_is\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20unsigned\20long*\29\20const
+499:std::__2::ctype<wchar_t>::do_scan_is\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const
+500:std::__2::ctype<wchar_t>::do_scan_not\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const
+501:std::__2::ctype<wchar_t>::do_toupper\28wchar_t\29\20const
+502:std::__2::ctype<wchar_t>::do_toupper\28wchar_t*\2c\20wchar_t\20const*\29\20const
+503:std::__2::ctype<wchar_t>::do_tolower\28wchar_t\29\20const
+504:std::__2::ctype<wchar_t>::do_tolower\28wchar_t*\2c\20wchar_t\20const*\29\20const
+505:std::__2::ctype<wchar_t>::do_widen\28char\29\20const
+506:std::__2::ctype<wchar_t>::do_widen\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const
+507:std::__2::ctype<wchar_t>::do_narrow\28wchar_t\2c\20char\29\20const
+508:std::__2::ctype<wchar_t>::do_narrow\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20char\2c\20char*\29\20const
+509:std::__2::ctype<char>::~ctype\28\29
+510:std::__2::ctype<char>::~ctype\28\29_1235
+511:std::__2::ctype<char>::do_toupper\28char\29\20const
+512:std::__2::ctype<char>::do_toupper\28char*\2c\20char\20const*\29\20const
+513:std::__2::ctype<char>::do_tolower\28char\29\20const
+514:std::__2::ctype<char>::do_tolower\28char*\2c\20char\20const*\29\20const
+515:std::__2::ctype<char>::do_widen\28char\20const*\2c\20char\20const*\2c\20char*\29\20const
+516:std::__2::ctype<char>::do_narrow\28char\2c\20char\29\20const
+517:std::__2::ctype<char>::do_narrow\28char\20const*\2c\20char\20const*\2c\20char\2c\20char*\29\20const
+518:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>::do_out\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+519:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+520:std::__2::codecvt<char\2c\20char\2c\20__mbstate_t>::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const
+521:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::~codecvt\28\29_1253
+522:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::do_out\28__mbstate_t&\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+523:std::__2::__libcpp_wcrtomb_l\5babi:nn180100\5d\28char*\2c\20wchar_t\2c\20__mbstate_t*\2c\20__locale_struct*\29
+524:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20wchar_t*\2c\20wchar_t*\2c\20wchar_t*&\29\20const
+525:std::__2::__libcpp_mbrtowc_l\5babi:nn180100\5d\28wchar_t*\2c\20char\20const*\2c\20unsigned\20long\2c\20__mbstate_t*\2c\20__locale_struct*\29
+526:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+527:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::do_encoding\28\29\20const
+528:std::__2::__libcpp_mb_cur_max_l\5babi:nn180100\5d\28__locale_struct*\29
+529:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const
+530:std::__2::codecvt<wchar_t\2c\20char\2c\20__mbstate_t>::do_max_length\28\29\20const
+531:std::__2::codecvt<char16_t\2c\20char\2c\20__mbstate_t>::do_out\28__mbstate_t&\2c\20char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+532:std::__2::codecvt<char16_t\2c\20char\2c\20__mbstate_t>::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char16_t*\2c\20char16_t*\2c\20char16_t*&\29\20const
+533:std::__2::codecvt<char16_t\2c\20char\2c\20__mbstate_t>::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const
+534:std::__2::codecvt<char16_t\2c\20char\2c\20__mbstate_t>::do_max_length\28\29\20const
+535:std::__2::codecvt<char32_t\2c\20char\2c\20__mbstate_t>::do_out\28__mbstate_t&\2c\20char32_t\20const*\2c\20char32_t\20const*\2c\20char32_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const
+536:std::__2::codecvt<char32_t\2c\20char\2c\20__mbstate_t>::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char32_t*\2c\20char32_t*\2c\20char32_t*&\29\20const
+537:std::__2::codecvt<char32_t\2c\20char\2c\20__mbstate_t>::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const
+538:std::__2::numpunct<char>::~numpunct\28\29
+539:std::__2::numpunct<char>::~numpunct\28\29_1307
+540:std::__2::numpunct<wchar_t>::~numpunct\28\29
+541:std::__2::numpunct<wchar_t>::~numpunct\28\29_1309
+542:std::__2::numpunct<char>::do_decimal_point\28\29\20const
+543:std::__2::numpunct<char>::do_thousands_sep\28\29\20const
+544:std::__2::numpunct<char>::do_grouping\28\29\20const
+545:std::__2::numpunct<wchar_t>::do_grouping\28\29\20const
+546:std::__2::numpunct<char>::do_truename\28\29\20const
+547:std::__2::numpunct<wchar_t>::do_truename\28\29\20const
+548:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::basic_string\5babi:nn180100\5d<0>\28wchar_t\20const*\29
+549:std::__2::numpunct<char>::do_falsename\28\29\20const
+550:std::__2::numpunct<wchar_t>::do_falsename\28\29\20const
+551:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::operator=\5babi:nn180100\5d\28char\20const*\29
+552:std::__2::__time_get_c_storage<char>::__weeks\28\29\20const
+553:__cxx_global_array_dtor.58
+554:std::__2::__time_get_c_storage<wchar_t>::__weeks\28\29\20const
+555:__cxx_global_array_dtor.73
+556:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::operator=\5babi:nn180100\5d\28wchar_t\20const*\29
+557:std::__2::__time_get_c_storage<char>::__months\28\29\20const
+558:__cxx_global_array_dtor.88
+559:std::__2::__time_get_c_storage<wchar_t>::__months\28\29\20const
+560:__cxx_global_array_dtor.112
+561:std::__2::__time_get_c_storage<char>::__am_pm\28\29\20const
+562:__cxx_global_array_dtor.136
+563:std::__2::__time_get_c_storage<wchar_t>::__am_pm\28\29\20const
+564:__cxx_global_array_dtor.139
+565:std::__2::__time_get_c_storage<char>::__x\28\29\20const
+566:__cxx_global_array_dtor.32
+567:std::__2::__time_get_c_storage<wchar_t>::__x\28\29\20const
+568:__cxx_global_array_dtor.34
+569:std::__2::__time_get_c_storage<char>::__X\28\29\20const
+570:__cxx_global_array_dtor.35
+571:std::__2::__time_get_c_storage<wchar_t>::__X\28\29\20const
+572:__cxx_global_array_dtor.37
+573:std::__2::__time_get_c_storage<char>::__c\28\29\20const
+574:__cxx_global_array_dtor.39
+575:std::__2::__time_get_c_storage<wchar_t>::__c\28\29\20const
+576:__cxx_global_array_dtor.41
+577:std::__2::__time_get_c_storage<char>::__r\28\29\20const
+578:__cxx_global_array_dtor.43
+579:std::__2::__time_get_c_storage<wchar_t>::__r\28\29\20const
+580:__cxx_global_array_dtor.45
+581:std::__2::time_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::~time_put\28\29
+582:std::__2::time_put<char\2c\20std::__2::ostreambuf_iterator<char\2c\20std::__2::char_traits<char>>>::~time_put\28\29_1373
+583:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29
+584:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::__recommend\5babi:nn180100\5d\28unsigned\20long\29
+585:std::__2::__allocation_result<std::__2::allocator_traits<std::__2::allocator<wchar_t>>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d<std::__2::allocator<wchar_t>>\28std::__2::allocator<wchar_t>&\2c\20unsigned\20long\29
+586:std::__2::allocator<wchar_t>::allocate\5babi:nn180100\5d\28unsigned\20long\29
+587:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__null_terminate_at\5babi:nn180100\5d\28char*\2c\20unsigned\20long\29
+588:std::__2::allocator<wchar_t>::deallocate\5babi:nn180100\5d\28wchar_t*\2c\20unsigned\20long\29
+589:bool\20std::__2::__is_pointer_in_range\5babi:nn180100\5d<char\2c\20char\2c\200>\28char\20const*\2c\20char\20const*\2c\20char\20const*\29
+590:std::__2::__unwrap_iter_impl<std::__2::__wrap_iter<char*>\2c\20true>::__unwrap\5babi:nn180100\5d\28std::__2::__wrap_iter<char*>\29
+591:std::__2::__to_address_helper<std::__2::__wrap_iter<char*>\2c\20void>::__call\5babi:nn180100\5d\28std::__2::__wrap_iter<char*>\20const&\29
+592:auto\20std::__2::__unwrap_range\5babi:nn180100\5d<std::__2::__wrap_iter<char\20const*>\2c\20std::__2::__wrap_iter<char\20const*>>\28std::__2::__wrap_iter<char\20const*>\2c\20std::__2::__wrap_iter<char\20const*>\29
+593:std::__2::__compressed_pair_elem<std::__2::locale::facet**\2c\200\2c\20false>::__compressed_pair_elem\5babi:nn180100\5d<std::nullptr_t\2c\20void>\28std::nullptr_t&&\29
+594:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::max_size\28\29\20const
+595:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::__alloc\5babi:nn180100\5d\28\29
+596:std::__2::__allocation_result<std::__2::allocator_traits<std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d<std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>\28std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>&\2c\20unsigned\20long\29
+597:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::__end_cap\5babi:nn180100\5d\28\29
+598:std::__2::locale::facet**\20std::__2::__construct_at\5babi:nn180100\5d<std::__2::locale::facet*\2c\20std::__2::locale::facet**>\28std::__2::locale::facet**\29
+599:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::__base_destruct_at_end\5babi:nn180100\5d\28std::__2::locale::facet**\29
+600:std::__2::vector<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::capacity\5babi:nn180100\5d\28\29\20const
+601:std::__2::allocator_traits<std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>>::deallocate\5babi:nn180100\5d\28std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>&\2c\20std::__2::locale::facet**\2c\20unsigned\20long\29
+602:std::__2::__split_buffer<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>&>::__alloc\5babi:nn180100\5d\28\29
+603:std::__2::__split_buffer<std::__2::locale::facet*\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>&>::__end_cap\5babi:nn180100\5d\28\29
+604:std::__2::__compressed_pair<std::__2::locale::facet**\2c\20std::__2::__sso_allocator<std::__2::locale::facet*\2c\2030ul>&>::second\5babi:nn180100\5d\28\29
+605:std::__2::reverse_iterator<std::__2::locale::facet**>::operator*\5babi:nn180100\5d\28\29\20const
+606:std::__2::reverse_iterator<std::__2::locale::facet**>::operator++\5babi:nn180100\5d\28\29
+607:std::__2::__constexpr_wcslen\5babi:nn180100\5d\28wchar_t\20const*\29
+608:std::__2::__time_put::__time_put\5babi:nn180100\5d\28\29
+609:strtoll_l
+610:strtoull_l
+611:std::__2::__shared_count::~__shared_count\28\29_1673
+612:operator\20new\28unsigned\20long\29
+613:std::exception::exception\5babi:nn180100\5d\28\29
+614:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20char\20const*\29
+615:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::~basic_string\28\29
+616:std::__2::char_traits<char>::assign\5babi:nn180100\5d\28char*\2c\20unsigned\20long\2c\20char\29
+617:std::__2::basic_string<char\2c\20std::__2::char_traits<char>\2c\20std::__2::allocator<char>>::push_back\28char\29
+618:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20wchar_t\20const*\29
+619:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::~basic_string\28\29
+620:std::__2::basic_string<wchar_t\2c\20std::__2::char_traits<wchar_t>\2c\20std::__2::allocator<wchar_t>>::push_back\28wchar_t\29
+621:__cxa_allocate_exception
+622:is_equal\28std::type_info\20const*\2c\20std::type_info\20const*\2c\20bool\29
+623:__cxxabiv1::__class_type_info::can_catch\28__cxxabiv1::__shim_type_info\20const*\2c\20void*&\29\20const
+624:__cxxabiv1::__class_type_info::process_found_base_class\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const
+625:__cxxabiv1::__class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const
+626:__cxxabiv1::__si_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const
+627:__cxxabiv1::__base_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const
+628:update_offset_to_base\28char\20const*\2c\20long\29
+629:__cxxabiv1::__vmi_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const
+630:__cxxabiv1::__class_type_info::process_static_type_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\29\20const
+631:__cxxabiv1::__class_type_info::process_static_type_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\29\20const
+632:__cxxabiv1::__vmi_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+633:__cxxabiv1::__base_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+634:__cxxabiv1::__base_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+635:__cxxabiv1::__si_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+636:__cxxabiv1::__class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+637:__cxxabiv1::__vmi_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+638:__cxxabiv1::__si_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+639:__cxxabiv1::__class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const
+640:std::exception::what\28\29\20const
+641:std::bad_alloc::what\28\29\20const
+642:std::bad_array_new_length::what\28\29\20const
+643:std::logic_error::~logic_error\28\29
+644:std::logic_error::~logic_error\28\29_1772
+645:_emscripten_stack_restore
+646:_emscripten_stack_alloc
+647:emscripten_stack_get_current
+648:legalstub$dynCall_viijii
+649:legalstub$dynCall_jiji
+650:legalstub$dynCall_iiiiij
+651:legalstub$dynCall_iiiiijj
+652:legalstub$dynCall_iiiiiijj
diff --git a/wasm/gcc-loops/build/gcc-loops.wasm b/wasm/gcc-loops/build/gcc-loops.wasm
new file mode 100755
index 0000000..44cf0eb
--- /dev/null
+++ b/wasm/gcc-loops/build/gcc-loops.wasm
Binary files differ
diff --git a/wasm/gcc-loops.cpp b/wasm/gcc-loops/gcc-loops.cpp
similarity index 94%
rename from wasm/gcc-loops.cpp
rename to wasm/gcc-loops/gcc-loops.cpp
index 2b01370..2230825 100644
--- a/wasm/gcc-loops.cpp
+++ b/wasm/gcc-loops/gcc-loops.cpp
@@ -159,10 +159,10 @@
/* feature: support data-types of different sizes.
- Currently only a single vector-size per target is supported;
- it can accommodate n elements such that n = vector-size/element-size
- (e.g, 4 ints, 8 shorts, or 16 chars for a vector of size 16 bytes).
- A combination of data-types of different sizes in the same loop
+ Currently only a single vector-size per target is supported;
+ it can accommodate n elements such that n = vector-size/element-size
+ (e.g, 4 ints, 8 shorts, or 16 chars for a vector of size 16 bytes).
+ A combination of data-types of different sizes in the same loop
requires special handling. This support is now present in mainline,
and also includes support for type conversions. */
__attribute__((noinline))
@@ -316,7 +316,7 @@
us = End.tv_usec - Start.tv_usec;
mtime = (s*1000 + us/1000.0)+0.5;
if (Print)
- std::cout<<Title<<", "<<mtime<<", msec\n";
+ std::cout<<Title<<", "<<std::dec<<mtime<<", msec\n";
}
private:
@@ -369,6 +369,9 @@
BENCH("Example1", example1(), Mi*10, digest_memory(&a[0], &a[256]));
BENCH("Example2a", example2a(N, 2), Mi*4, digest_memory(&b[0], &b[N]));
BENCH("Example2b", example2b(N, 2), Mi*2, digest_memory(&a[0], &a[N]));
+ // dlehmann: Emscripten 3.1.73 warns for the following four examples:
+ // gcc-loops.cpp:375:35: warning: passing 4-byte aligned argument to 16-byte aligned parameter 2 of 'example3' may result in an unaligned pointer access [-Walign-mismatch]
+ // This is a false positive, since `__alignof__(ia) == 16`.
BENCH("Example3", example3(N, ia, ib), Mi*2, digest_memory(&ia[0], &ia[N]));
BENCH("Example4a", example4a(N, ia, ib), Mi*2, digest_memory(&ia[0], &ia[N]));
BENCH("Example4b", example4b(N-10, ia, ib), Mi*2, digest_memory(&ia[0], &ia[N]));
@@ -380,7 +383,7 @@
BENCH("Example10b", example10b(sa,sb,sc,ia,ib,ic), Mi*4, digest_memory(&ia[0], &ia[N]));
BENCH("Example11", example11(), Mi*2, digest_memory(&d[0], &d[N]));
BENCH("Example12", example12(), Mi*4, digest_memory(&a[0], &a[N]));
- //BENCH("Example21", example21(ia, N), Mi*4, digest_memory(&ia[0], &ia[N]));
+ BENCH("Example21", example21(ia, N), Mi*4, digest_memory(&ia[0], &ia[N]));
BENCH("Example23", example23(usa,ua), Mi*8, digest_memory(&usa[0], &usa[256]));
BENCH("Example24", example24(2,4), Mi*2, 0);
BENCH("Example25", example25(), Mi*2, digest_memory(&dj[0], &dj[N]));
@@ -394,6 +397,3 @@
return 0;
}
-
-
-
diff --git a/wasm/tfjs-benchmark.js b/wasm/tfjs/benchmark.js
similarity index 69%
rename from wasm/tfjs-benchmark.js
rename to wasm/tfjs/benchmark.js
index 0a9bf45..b178fd0 100644
--- a/wasm/tfjs-benchmark.js
+++ b/wasm/tfjs/benchmark.js
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Apple Inc. All rights reserved.
+ * Copyright (C) 2023-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,19 +23,20 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-async function doRun() {
- if (!isInBrowser) {
- globalThis.tfjsBackendWasmSimdBlob = Module.tfjsBackendWasmSimdBlob;
- globalThis.tfjsBackendWasmBlob = Module.tfjsBackendWasmBlob;
+class Benchmark {
+ firstIteration = true;
+ async runIteration() {
+ if (this.firstIteration) {
+ this.firstIteration = false;
+ if (!isInBrowser) {
+ globalThis.tfjsBackendWasmSimdBlob = Module.tfjsBackendWasmSimdBlob;
+ globalThis.tfjsBackendWasmBlob = Module.tfjsBackendWasmBlob;
+ }
+
+ // setWasmBackend calls loadAndPredict()
+ return await setWasmBackend();
+ }
+
+ return await loadAndPredict();
}
-
- let start = benchmarkTime();
- await setWasmBackend();
- let compileTime = benchmarkTime() - start;
- reportCompileTime(compileTime);
-
- start = benchmarkTime();
- for (let i = 0; i < 5; ++i)
- await loadAndPredict();
- reportRunTime(benchmarkTime() - start)
-}
+};
diff --git a/wasm/tfjs-backend-wasm-simd.wasm b/wasm/tfjs/tfjs-backend-wasm-simd.wasm
similarity index 100%
rename from wasm/tfjs-backend-wasm-simd.wasm
rename to wasm/tfjs/tfjs-backend-wasm-simd.wasm
Binary files differ
diff --git a/wasm/tfjs-backend-wasm.wasm b/wasm/tfjs/tfjs-backend-wasm.wasm
similarity index 100%
rename from wasm/tfjs-backend-wasm.wasm
rename to wasm/tfjs/tfjs-backend-wasm.wasm
Binary files differ
diff --git a/wasm/tfjs-bundle.js b/wasm/tfjs/tfjs-bundle.js
similarity index 100%
rename from wasm/tfjs-bundle.js
rename to wasm/tfjs/tfjs-bundle.js
diff --git a/wasm/tfjs-model-coco-ssd.js b/wasm/tfjs/tfjs-model-coco-ssd.js
similarity index 100%
rename from wasm/tfjs-model-coco-ssd.js
rename to wasm/tfjs/tfjs-model-coco-ssd.js
diff --git a/wasm/tfjs-model-helpers.js b/wasm/tfjs/tfjs-model-helpers.js
similarity index 100%
rename from wasm/tfjs-model-helpers.js
rename to wasm/tfjs/tfjs-model-helpers.js
diff --git a/wasm/tfjs-model-mobilenet-v1.js b/wasm/tfjs/tfjs-model-mobilenet-v1.js
similarity index 100%
rename from wasm/tfjs-model-mobilenet-v1.js
rename to wasm/tfjs/tfjs-model-mobilenet-v1.js
diff --git a/wasm/tfjs-model-mobilenet-v3.js b/wasm/tfjs/tfjs-model-mobilenet-v3.js
similarity index 100%
rename from wasm/tfjs-model-mobilenet-v3.js
rename to wasm/tfjs/tfjs-model-mobilenet-v3.js
diff --git a/wasm/tfjs-model-use-vocab.js b/wasm/tfjs/tfjs-model-use-vocab.js
similarity index 100%
rename from wasm/tfjs-model-use-vocab.js
rename to wasm/tfjs/tfjs-model-use-vocab.js
diff --git a/wasm/tfjs-model-use.js b/wasm/tfjs/tfjs-model-use.js
similarity index 100%
rename from wasm/tfjs-model-use.js
rename to wasm/tfjs/tfjs-model-use.js
diff --git a/wasm/tfjs.js b/wasm/tfjs/tfjs.js
similarity index 100%
rename from wasm/tfjs.js
rename to wasm/tfjs/tfjs.js
diff --git a/worker/bomb-subtests/crypto-md5.js b/worker/bomb-subtests/crypto-md5.js
index a93bedb..938081c 100644
--- a/worker/bomb-subtests/crypto-md5.js
+++ b/worker/bomb-subtests/crypto-md5.js
@@ -181,9 +181,7 @@
*/
function safe_add(x, y)
{
- var lsw = (x & 0xFFFF) + (y & 0xFFFF);
- var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
- return (msw << 16) | (lsw & 0xFFFF);
+ return ((x & 0xffffffff) + (y & 0xffffffff)) & 0xffffffff
}
/*
diff --git a/worker/bomb-subtests/crypto-sha1.js b/worker/bomb-subtests/crypto-sha1.js
index abea4b1..5cd0c5d 100644
--- a/worker/bomb-subtests/crypto-sha1.js
+++ b/worker/bomb-subtests/crypto-sha1.js
@@ -127,9 +127,7 @@
*/
function safe_add(x, y)
{
- var lsw = (x & 0xFFFF) + (y & 0xFFFF);
- var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
- return (msw << 16) | (lsw & 0xFFFF);
+ return ((x & 0xffffffff) + (y & 0xffffffff)) & 0xffffffff
}
/*