UNPKG

@livestore/sqlite-wasm

Version:

SQLite Wasm conveniently wrapped as an ES Module.

1,394 lines (1,283 loc) • 883 kB
/* ** 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.46.0" ** SQLITE_VERSION_NUMBER 3046000 ** SQLITE_SOURCE_ID "2024-03-07 12:34:26 720ce06d93a9e4cc25c34c873c82165d8801f208c22701e51538f3210de8alt1" ** ** Using the Emscripten SDK version emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.47-git. */ var sqlite3InitModule = (() => { var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; return function (moduleArg = {}) { // 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(Module) { ..generated code.. } // 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; Module['ready'] = new Promise((resolve, reject) => { readyPromiseResolve = resolve; readyPromiseReject = reject; }); // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) /** * 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; } sqlite3InitModuleState.debugModule( 'locateFile(', arguments[0], ',', arguments[1], ')', 'sqlite3InitModuleState.scriptDir =', this.scriptDir, 'up.entries() =', Array.from(up.entries()), 'result =', theFile, ); return theFile; }.bind(sqlite3InitModuleState); /** * Bug warning: a custom Module.instantiateWasm() does not work in WASMFS * builds: * * https://github.com/emscripten-core/emscripten/issues/17951 * * In such builds we must disable this. */ const xNameOfInstantiateWasm = false ? 'instantiateWasm' : 'emscripten-bug-17951'; Module[xNameOfInstantiateWasm] = function callee(imports, onSuccess) { imports.env.foo = function () {}; const uri = Module.locateFile( callee.uri, 'undefined' === typeof scriptDirectory /*var defined by Emscripten glue*/ ? '' : scriptDirectory, ); sqlite3InitModuleState.debugModule('instantiateWasm() uri =', uri); const wfetch = () => fetch(uri, { credentials: 'same-origin' }); const loadWasm = WebAssembly.instantiateStreaming ? async () => { return WebAssembly.instantiateStreaming(wfetch(), imports).then( (arg) => onSuccess(arg.instance, arg.module), ); } : async () => { // Safari < v15 return wfetch() .then((response) => response.arrayBuffer()) .then((bytes) => WebAssembly.instantiate(bytes, imports)) .then((arg) => onSuccess(arg.instance, arg.module)); }; loadWasm(); return {}; }; /* It is literally impossible to reliably get the name of _this_ script at runtime, so impossible to derive X.wasm from script name X.js. Thus we need, at build-time, to redefine Module[xNameOfInstantiateWasm].uri by appending it to a build-specific copy of this file with the name of the wasm file. This is apparently why Emscripten hard-codes the name of the wasm file into their glue scripts. */ Module[xNameOfInstantiateWasm].uri = 'sqlite3.wasm'; /* 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. */ // 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; }; // 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 importScripts == 'function'; // 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'; var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; // `/` 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 read_, 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 (_scriptDir) { scriptDirectory = _scriptDir; } // 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.indexOf('blob:') !== 0) { scriptDirectory = scriptDirectory.substr( 0, scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1, ); } else { scriptDirectory = ''; } // Differentiate the Web Worker from the Node Worker case, as reading must // be done differently. { // include: web_or_worker_shell_read.js read_ = (url) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(null); return xhr.responseText; }; 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, onload, onerror) => { 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 onload(xhr.response); return; } onerror(); }; xhr.onerror = onerror; xhr.send(null); }; // 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 e.g. in memoryInitializerRequest, which is a large typed array. 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']; if (Module['quit']) quit_ = Module['quit']; // 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; if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; if (typeof WebAssembly != 'object') { abort('no native wasm support detected'); } // 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; /** @type {function( any , 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() implemenation 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; 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); } // In non-standalone/normal mode, we create the memory here. // include: runtime_init_memory.js // Create the wasm memory. (Note: this only applies if IMPORTED_MEMORY is defined) var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216; assert( INITIAL_MEMORY >= 524288, 'INITIAL_MEMORY should be larger than STACK_SIZE, was ' + INITIAL_MEMORY + '! (STACK_SIZE=' + 524288 + ')', ); // check for full engine support (use string 'subarray' to avoid closure compiler confusion) if (Module['wasmMemory']) { wasmMemory = Module['wasmMemory']; } else { wasmMemory = new WebAssembly.Memory({ initial: INITIAL_MEMORY / 65536, // In theory we should not need to emit the maximum if we want "unlimited" // or 4GB of memory, but VMs error on that atm, see // https://github.com/emscripten-core/emscripten/issues/14130 // And in the pthreads case we definitely need to emit a maximum. So // always emit one. maximum: 2147483648 / 65536, }); } updateMemoryViews(); // If the user provides an incorrect length, just use that length instead rather than providing the user to // specifically provide the memory length with Module['INITIAL_MEMORY']. INITIAL_MEMORY = wasmMemory.buffer.byteLength; // end include: runtime_init_memory.js // include: runtime_stack_check.js // end include: runtime_stack_check.js // include: runtime_assertions.js // end include: runtime_assertions.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.init.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++; 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(); // can add another dependenciesFulfilled } } } /** @param {string | number} [what] */ function abort(what) { if (Module['onAbort']) { 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; EXITSTATUS = 1; 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 // defintion 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 var wasmBinaryFile; wasmBinaryFile = 'sqlite3.wasm'; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(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, try to load it asynchronously. // 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 fetch if it is available and the url is not a file, otherwise fall back to XHR. if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { if (typeof fetch == 'function') { return fetch(binaryFile, { credentials: 'same-origin' }) .then((response) => { if (!response['ok']) { throw "failed to load wasm binary file at '" + binaryFile + "'"; } return response['arrayBuffer'](); }) .catch(() => 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((instance) => { return instance; }) .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); } // Create the wasm instance. // Receives the wasm imports, returns the exports. function createWasm() { // prepare imports var info = { env: wasmImports, wasi_snapshot_preview1: wasmImports, }; // 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; 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); } } // 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 */ function ExitStatus(status) { this.name = 'ExitStatus'; 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 >> 0]; case 'i8': return HEAP8[ptr >> 0]; 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 >> 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': 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 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: function () { var paths = Array.prototype.slice.call(arguments); return PATH.normalize(paths.join('/')); }, join2: (l, r) => { return PATH.normalize(l + '/' + r); }, }; var initRandomFill = () => { if ( typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function' ) { // for modern web browsers return (view) => crypto.getRandomValues(view); } // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096 else abort('initRandomDevice'); }; var randomFill = (view) => { // Lazily init on the first invocation. return (randomFill = initRandomFill())(view); }; var PATH_FS = { 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) { 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('utf8') : 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] * @returns {string} */ var UTF8ArrayToString = (heapOrArray, idx, maxBytesToRead) => { 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 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; }; 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 (typeof readline == 'function') { // Command line. result = readline(); if (result !== null) { result += '\n'; } } 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, 0)); 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, 0)); 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, 0)); tty.output = []; } else { if (val != 0) tty.output.push(val); } }, fsync(tty) { if (tty.output && tty.output.length > 0) { err(UTF8ArrayToString(tty.output, 0)); tty.output = []; } }, }, }; var zeroMemory = (address, size) => { HEAPU8.fill(0, address, address + size); return address; }; 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) return 0; return zeroMemory(ptr, size); }; 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); } 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; // 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