diff --git a/.gitignore b/.gitignore index 93524df8..2ce24238 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ build/ # VS project and working files *.vcxproj.user .vs/ +.vscode/ Debug/ Release/ x64/ diff --git a/encoder/basisu_comp.cpp b/encoder/basisu_comp.cpp index 59a2a509..7cf7323a 100644 --- a/encoder/basisu_comp.cpp +++ b/encoder/basisu_comp.cpp @@ -1722,7 +1722,7 @@ namespace basisu if ((!m_params.m_hdr) && (m_params.m_source_mipmap_images.size())) { // User-provided mipmaps for each layer or image in the texture array. - for (uint32_t mip_index = 0; mip_index < m_params.m_source_mipmap_images[source_file_index].size(); mip_index++) + for (uint32_t mip_index = 1; mip_index < m_params.m_source_mipmap_images[source_file_index].size(); mip_index++) { image& mip_img = m_params.m_source_mipmap_images[source_file_index][mip_index]; @@ -1748,7 +1748,7 @@ namespace basisu else if ((m_params.m_hdr) && (m_params.m_source_mipmap_images_hdr.size())) { // User-provided mipmaps for each layer or image in the texture array. - for (uint32_t mip_index = 0; mip_index < m_params.m_source_mipmap_images_hdr[source_file_index].size(); mip_index++) + for (uint32_t mip_index = 1; mip_index < m_params.m_source_mipmap_images_hdr[source_file_index].size(); mip_index++) { imagef& mip_img = m_params.m_source_mipmap_images_hdr[source_file_index][mip_index]; diff --git a/webgl/encoder/build/basis_encoder.js b/webgl/encoder/build/basis_encoder.js index 3fb6e1ae..f1906034 100644 --- a/webgl/encoder/build/basis_encoder.js +++ b/webgl/encoder/build/basis_encoder.js @@ -1,16 +1,17 @@ var BASIS = (() => { - var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; - if (typeof __filename != 'undefined') _scriptName ||= __filename; + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; return ( -function(moduleArg = {}) { - var moduleRtn; +function(BASIS) { + BASIS = BASIS || {}; + + -// 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 +// 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). @@ -20,37 +21,20 @@ function(moduleArg = {}) { // 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; +var Module = typeof BASIS != 'undefined' ? BASIS : {}; + +// See https://caniuse.com/mdn-javascript_builtins_object_assign // Set up the promise that indicates the Module is initialized var readyPromiseResolve, readyPromiseReject; -var readyPromise = new Promise((resolve, reject) => { +Module['ready'] = new Promise(function(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 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; - -if (ENVIRONMENT_IS_NODE) { - // `require()` is no-op in an ESM module, use `createRequire()` to construct - // the require()` function. This is only necessary for multi-environment - // builds, `-sENVIRONMENT=node` emits a static import declaration instead. - // TODO: Swap all `require()`'s with `import()`'s? - -} - // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) - +// {{PRE_JSES}} // Sometimes an existing Module object exists with properties // meant to overwrite the default module functionality. Here @@ -65,6 +49,17 @@ 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) { @@ -75,50 +70,105 @@ function locateFile(path) { } // Hooks that are implemented differently in different runtime environments. -var readAsync, readBinary; +var read_, + readAsync, + readBinary, + setWindowTitle; + +// Normally we don't log exceptions but instead let them bubble out the top +// level where the embedding environment (e.g. the browser) can handle +// them. +// However under v8 and node we sometimes exit the process direcly in which case +// its up to use us to log the exception before exiting. +// If we fix https://github.com/emscripten-core/emscripten/issues/15080 +// this may no longer be needed under node. +function logExceptionOnExit(e) { + if (e instanceof ExitStatus) return; + let toLog = e; + err('exiting due to exception: ' + toLog); +} + +var fs; +var nodePath; +var requireNodeFS; if (ENVIRONMENT_IS_NODE) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = require('path').dirname(scriptDirectory) + '/'; + } else { + scriptDirectory = __dirname + '/'; + } - // 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'); +// include: node_shell_read.js - scriptDirectory = __dirname + '/'; -// include: node_shell_read.js +requireNodeFS = () => { + // Use nodePath as the indicator for these not being initialized, + // since in some environments a global fs may have already been + // created. + if (!nodePath) { + fs = require('fs'); + nodePath = require('path'); + } +}; + +read_ = function shell_read(filename, binary) { + requireNodeFS(); + filename = nodePath['normalize'](filename); + return fs.readFileSync(filename, binary ? undefined : 'utf8'); +}; + 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); + var ret = read_(filename, true); + if (!ret.buffer) { + ret = new Uint8Array(ret); + } 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); - }); +readAsync = (filename, onload, onerror) => { + requireNodeFS(); + filename = nodePath['normalize'](filename); + fs.readFile(filename, function(err, data) { + if (err) onerror(err); + else onload(data.buffer); }); }; + // end include: node_shell_read.js - if (!Module['thisProgram'] && process.argv.length > 1) { - thisProgram = process.argv[1].replace(/\\/g, '/'); + if (process['argv'].length > 1) { + thisProgram = process['argv'][1].replace(/\\/g, '/'); } - arguments_ = process.argv.slice(2); + arguments_ = process['argv'].slice(2); // MODULARIZE will export the module in the proper place outside, we don't need to export here + process['on']('uncaughtException', function(ex) { + // suppress ExitStatus exceptions from showing an error + if (!(ex instanceof ExitStatus)) { + throw ex; + } + }); + + // Without this older versions of node (< v15) will log unhandled rejections + // but return 0, which is not normally the desired behaviour. This is + // not be needed with node v15 and about because it is now the default + // behaviour: + // See https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode + process['on']('unhandledRejection', function(reason) { throw reason; }); + quit_ = (status, toThrow) => { - process.exitCode = status; - throw toThrow; + if (keepRuntimeAlive()) { + process['exitCode'] = status; + throw toThrow; + } + logExceptionOnExit(toThrow); + process['exit'](status); }; + Module['inspect'] = function () { return '[Emscripten Module object]'; }; + } else // Note that this includes Node.js workers when relevant (pthreads is enabled). @@ -132,8 +182,8 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { } // 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; + 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. @@ -141,65 +191,65 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { // 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 = ''; + if (scriptDirectory.indexOf('blob:') !== 0) { + scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf('/')+1); } else { - scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/')+1); + scriptDirectory = ''; } + // Differentiate the Web Worker from the Node Worker case, as reading must + // be done differently. { // include: web_or_worker_shell_read.js -if (ENVIRONMENT_IS_WORKER) { - readBinary = (url) => { + + + read_ = (url) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); - xhr.responseType = 'arraybuffer'; xhr.send(null); - return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response)); - }; + return xhr.responseText; } - 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((reject, resolve) => { + if (ENVIRONMENT_IS_WORKER) { + readBinary = (url) => { var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); + xhr.open('GET', url, false); xhr.responseType = 'arraybuffer'; - xhr.onload = () => { - if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 - resolve(xhr.response); - } - 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)); - }) - }; + 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 } + + setWindowTitle = (title) => document.title = title; } else { } var out = Module['print'] || console.log.bind(console); -var err = Module['printErr'] || console.error.bind(console); +var err = Module['printErr'] || console.warn.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. +// 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 @@ -214,9 +264,234 @@ 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 + + + +var STACK_ALIGN = 16; +var POINTER_SIZE = 4; + +function getNativeTypeSize(type) { + switch (type) { + case 'i1': case 'i8': case 'u8': return 1; + case 'i16': case 'u16': return 2; + case 'i32': case 'u32': return 4; + case 'i64': case 'u64': return 8; + case 'float': return 4; + case 'double': return 8; + default: { + if (type[type.length - 1] === '*') { + return POINTER_SIZE; + } else if (type[0] === 'i') { + const bits = Number(type.substr(1)); + assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); + return bits / 8; + } else { + return 0; + } + } + } +} + +function warnOnce(text) { + if (!warnOnce.shown) warnOnce.shown = {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + err(text); + } +} + +// include: runtime_functions.js + + +// This gives correct answers for everything less than 2^{14} = 16384 +// I hope nobody is contemplating functions with 16384 arguments... +function uleb128Encode(n) { + if (n < 128) { + return [n]; + } + return [(n % 128) | 128, n >> 7]; +} + +// Converts a signature like 'vii' into a description of the wasm types, like +// { parameters: ['i32', 'i32'], results: [] }. +function sigToWasmTypes(sig) { + var typeNames = { + 'i': 'i32', + 'j': 'i64', + 'f': 'f32', + 'd': 'f64', + 'p': 'i32', + }; + var type = { + parameters: [], + results: sig[0] == 'v' ? [] : [typeNames[sig[0]]] + }; + for (var i = 1; i < sig.length; ++i) { + type.parameters.push(typeNames[sig[i]]); + } + return type; +} + +// Wraps a JS function as a wasm function with a given signature. +function convertJsFunctionToWasm(func, sig) { + + // If the type reflection proposal is available, use the new + // "WebAssembly.Function" constructor. + // Otherwise, construct a minimal wasm module importing the JS function and + // re-exporting it. + if (typeof WebAssembly.Function == "function") { + return new WebAssembly.Function(sigToWasmTypes(sig), func); + } + + // The module is static, with the exception of the type section, which is + // generated based on the signature passed in. + var typeSection = [ + 0x01, // count: 1 + 0x60, // form: func + ]; + var sigRet = sig.slice(0, 1); + var sigParam = sig.slice(1); + var typeCodes = { + 'i': 0x7f, // i32 + 'p': 0x7f, // i32 + 'j': 0x7e, // i64 + 'f': 0x7d, // f32 + 'd': 0x7c, // f64 + }; + + // Parameters, length + signatures + typeSection = typeSection.concat(uleb128Encode(sigParam.length)); + for (var i = 0; i < sigParam.length; ++i) { + typeSection.push(typeCodes[sigParam[i]]); + } + + // Return values, length + signatures + // With no multi-return in MVP, either 0 (void) or 1 (anything else) + if (sigRet == 'v') { + typeSection.push(0x00); + } else { + typeSection = typeSection.concat([0x01, typeCodes[sigRet]]); + } + + // Write the section code and overall length of the type section into the + // section header + typeSection = [0x01 /* Type section code */].concat( + uleb128Encode(typeSection.length), + typeSection + ); + + // Rest of the module is static + var bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") + 0x01, 0x00, 0x00, 0x00, // version: 1 + ].concat(typeSection, [ + 0x02, 0x07, // import section + // (import "e" "f" (func 0 (type 0))) + 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00, + 0x07, 0x05, // export section + // (export "f" (func 0 (type 0))) + 0x01, 0x01, 0x66, 0x00, 0x00, + ])); + + // We can compile this wasm module synchronously because it is very small. + // This accepts an import (at "e.f"), that it reroutes to an export (at "f") + var module = new WebAssembly.Module(bytes); + var instance = new WebAssembly.Instance(module, { + 'e': { + 'f': func + } + }); + var wrappedFunc = instance.exports['f']; + return wrappedFunc; +} + +var freeTableIndexes = []; + +// Weak map of functions in the table to their indexes, created on first use. +var functionsInTableMap; + +function getEmptyTableSlot() { + // Reuse a free index if there is one, otherwise grow. + if (freeTableIndexes.length) { + return freeTableIndexes.pop(); + } + // Grow the table + try { + wasmTable.grow(1); + } catch (err) { + if (!(err instanceof RangeError)) { + throw err; + } + throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.'; + } + return wasmTable.length - 1; +} + +function updateTableMap(offset, count) { + for (var i = offset; i < offset + count; i++) { + var item = getWasmTableEntry(i); + // Ignore null values. + if (item) { + functionsInTableMap.set(item, i); + } + } +} + +/** + * Add a function to the table. + * 'sig' parameter is required if the function being added is a JS function. + * @param {string=} sig + */ +function addFunction(func, sig) { + + // Check if the function is already in the table, to ensure each function + // gets a unique index. First, create the map if this is the first use. + if (!functionsInTableMap) { + functionsInTableMap = new WeakMap(); + updateTableMap(0, wasmTable.length); + } + if (functionsInTableMap.has(func)) { + return functionsInTableMap.get(func); + } + + // It's not in the table, add it now. + + var ret = getEmptyTableSlot(); + + // Set the new value. + try { + // Attempting to call this with JS function will cause of table.set() to fail + setWasmTableEntry(ret, func); + } catch (err) { + if (!(err instanceof TypeError)) { + throw err; + } + var wrapped = convertJsFunctionToWasm(func, sig); + setWasmTableEntry(ret, wrapped); + } + + functionsInTableMap.set(func, ret); + + return ret; +} + +function removeFunction(index) { + functionsInTableMap.delete(getWasmTableEntry(index)); + freeTableIndexes.push(index); +} + +// end include: runtime_functions.js +// include: runtime_debug.js + + +// end include: runtime_debug.js +var tempRet0 = 0; +var setTempRet0 = (value) => { tempRet0 = value; }; +var getTempRet0 = () => tempRet0; + + + // === Preamble library stuff === // Documentation for the public APIs defined in this file must be updated in: @@ -227,8 +502,13 @@ if (Module['quit']) quit_ = Module['quit']; // 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; +var wasmBinary; if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; +var noExitRuntime = Module['noExitRuntime'] || true; + +if (typeof WebAssembly != 'object') { + abort('no native wasm support detected'); +} // Wasm globals @@ -247,23 +527,507 @@ var ABORT = false; // 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. + // the wild leave this simple abort() implemenation here for now. abort(text); } } +// Returns the C function with a specified identifier (for C++, you need to do manual name mangling) +function getCFunc(ident) { + var func = Module['_' + ident]; // closure exported function + return func; +} + +// C calling interface. +/** @param {string|null=} returnType + @param {Array=} argTypes + @param {Arguments|Array=} args + @param {Object=} opts */ +function ccall(ident, returnType, argTypes, args, opts) { + // For fast lookup of conversion functions + var toC = { + 'string': function(str) { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { // null string + // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' + var len = (str.length << 2) + 1; + ret = stackAlloc(len); + stringToUTF8(str, ret, len); + } + return ret; + }, + 'array': function(arr) { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + + function convertReturnValue(ret) { + if (returnType === 'string') { + + return UTF8ToString(ret); + } + if (returnType === 'boolean') return Boolean(ret); + return ret; + } + + 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); + function onDone(ret) { + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + + ret = onDone(ret); + return ret; +} + +/** @param {string=} returnType + @param {Array=} argTypes + @param {Object=} opts */ +function cwrap(ident, returnType, argTypes, opts) { + argTypes = argTypes || []; + // When the function takes numbers and returns a number, we can just return + // the original function + var numericArgs = argTypes.every(function(type){ return type === 'number'}); + var numericRet = returnType !== 'string'; + if (numericRet && numericArgs && !opts) { + return getCFunc(ident); + } + return function() { + return ccall(ident, returnType, argTypes, arguments, opts); + } +} + +// include: runtime_legacy.js + + +var ALLOC_NORMAL = 0; // Tries to use _malloc() +var ALLOC_STACK = 1; // Lives for the duration of the current function call + +/** + * allocate(): This function is no longer used by emscripten but is kept around to avoid + * breaking external users. + * You should normally not use allocate(), and instead allocate + * memory using _malloc()/stackAlloc(), initialize it with + * setValue(), and so forth. + * @param {(Uint8Array|Array)} slab: An array of data. + * @param {number=} allocator : How to allocate memory, see ALLOC_* + */ +function allocate(slab, allocator) { + var ret; + + if (allocator == ALLOC_STACK) { + ret = stackAlloc(slab.length); + } else { + ret = _malloc(slab.length); + } + + if (!slab.subarray && !slab.slice) { + slab = new Uint8Array(slab); + } + HEAPU8.set(slab, ret); + return ret; +} + +// end include: runtime_legacy.js +// include: runtime_strings.js + + +// runtime_strings.js: Strings related runtime functions that are part of both MINIMAL_RUNTIME and regular runtime. + +var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; + +// Given a pointer 'ptr' 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} + */ +function 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)); + } else { + 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. +// 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 +// style or the other. +/** + * @param {number} ptr + * @param {number=} maxBytesToRead + * @return {string} + */ +function UTF8ToString(ptr, maxBytesToRead) { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; +} + +// Copies the given Javascript String object 'str' to the given byte array at address 'outIdx', +// encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP. +// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. +// Parameters: +// str: the Javascript string to copy. +// heap: the array to copy to. Each index in this array is assumed to be one 8-byte element. +// outIdx: The starting offset in the array to begin the copying. +// maxBytesToWrite: The maximum number of bytes this function can write to the array. +// This count should include the null terminator, +// i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else. +// maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes. + 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; +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP. +// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF8(str, outPtr, maxBytesToWrite) { + return stringToUTF8Array(str, HEAPU8,outPtr, maxBytesToWrite); +} + +// Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte. +function 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 u = str.charCodeAt(i); // possibly a lead surrogate + 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; +} + +// end include: runtime_strings.js +// include: runtime_strings_extra.js + + +// runtime_strings_extra.js: Strings related runtime functions that are available only in regular runtime. + +// Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns +// a copy of that string as a Javascript String object. + +function AsciiToString(ptr) { + var str = ''; + while (1) { + var ch = HEAPU8[((ptr++)>>0)]; + if (!ch) return str; + str += String.fromCharCode(ch); + } +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP. + +function stringToAscii(str, outPtr) { + return writeAsciiToMemory(str, outPtr, false); +} + +// 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. + +var UTF16Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf-16le') : undefined; + +function UTF16ToString(ptr, maxBytesToRead) { + var endPtr = ptr; + // 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. + var idx = endPtr >> 1; + var maxIdx = idx + maxBytesToRead / 2; + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; + endPtr = idx << 1; + + if (endPtr - ptr > 32 && UTF16Decoder) { + return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); + } else { + var str = ''; + + // If maxBytesToRead is not passed explicitly, it will be undefined, and the for-loop's condition + // will always evaluate to true. The loop is then terminated on the first null char. + for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { + var codeUnit = HEAP16[(((ptr)+(i*2))>>1)]; + if (codeUnit == 0) break; + // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through. + str += String.fromCharCode(codeUnit); + } + + return str; + } +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP. +// Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write. +// Parameters: +// str: the Javascript string to copy. +// outPtr: Byte address in Emscripten HEAP where to write the string to. +// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null +// terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else. +// maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF16(str, outPtr, maxBytesToWrite) { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + if (maxBytesToWrite === undefined) { + maxBytesToWrite = 0x7FFFFFFF; + } + if (maxBytesToWrite < 2) return 0; + maxBytesToWrite -= 2; // Null terminator. + var startPtr = outPtr; + var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length; + for (var i = 0; i < numCharsToWrite; ++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)>>1)] = codeUnit; + outPtr += 2; + } + // Null-terminate the pointer to the HEAP. + HEAP16[((outPtr)>>1)] = 0; + return outPtr - startPtr; +} + +// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte. + +function lengthBytesUTF16(str) { + return str.length*2; +} + +function UTF32ToString(ptr, maxBytesToRead) { + var i = 0; + + var str = ''; + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + while (!(i >= maxBytesToRead / 4)) { + var utf32 = HEAP32[(((ptr)+(i*4))>>2)]; + if (utf32 == 0) break; + ++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. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + if (utf32 >= 0x10000) { + var ch = utf32 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } else { + str += String.fromCharCode(utf32); + } + } + return str; +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP. +// Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write. +// Parameters: +// str: the Javascript string to copy. +// outPtr: Byte address in Emscripten HEAP where to write the string to. +// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null +// terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else. +// maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF32(str, outPtr, maxBytesToWrite) { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + if (maxBytesToWrite === undefined) { + maxBytesToWrite = 0x7FFFFFFF; + } + if (maxBytesToWrite < 4) return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + 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! We must decode the string to UTF-32 to the heap. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var codeUnit = str.charCodeAt(i); // possibly a lead surrogate + if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) { + var trailSurrogate = str.charCodeAt(++i); + codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); + } + HEAP32[((outPtr)>>2)] = codeUnit; + outPtr += 4; + if (outPtr + 4 > endPtr) break; + } + // Null-terminate the pointer to the HEAP. + HEAP32[((outPtr)>>2)] = 0; + return outPtr - startPtr; +} + +// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte. + +function lengthBytesUTF32(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! We must decode the string to UTF-32 to the heap. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var codeUnit = str.charCodeAt(i); + if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate. + len += 4; + } + + return len; +} + +// Allocate heap space for a JS string, and write it there. +// It is the responsibility of the caller to free() that memory. +function allocateUTF8(str) { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8Array(str, HEAP8, ret, size); + return ret; +} + +// Allocate stack space for a JS string, and write it there. +function allocateUTF8OnStack(str) { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8Array(str, HEAP8, ret, size); + return ret; +} + +// Deprecated: This function should not be called because it is unsafe and does not provide +// a maximum length limit of how many bytes it is allowed to write. Prefer calling the +// function stringToUTF8Array() instead, which takes in a maximum length that can be used +// to be secure from out of bounds writes. +/** @deprecated + @param {boolean=} dontAddNull */ +function writeStringToMemory(string, buffer, dontAddNull) { + warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); + + var /** @type {number} */ lastChar, /** @type {number} */ end; + if (dontAddNull) { + // stringToUTF8Array always appends null. If we don't want to do that, remember the + // character that existed at the location where the null will be placed, and restore + // that after the write (below). + end = buffer + lengthBytesUTF8(string); + lastChar = HEAP8[end]; + } + stringToUTF8(string, buffer, Infinity); + if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. +} + +function writeArrayToMemory(array, buffer) { + HEAP8.set(array, buffer); +} + +/** @param {boolean=} dontAddNull */ +function writeAsciiToMemory(str, buffer, dontAddNull) { + for (var i = 0; i < str.length; ++i) { + HEAP8[((buffer++)>>0)] = str.charCodeAt(i); + } + // Null-terminate the pointer to the HEAP. + if (!dontAddNull) HEAP8[((buffer)>>0)] = 0; +} + +// end include: runtime_strings_extra.js // Memory management var HEAP, +/** @type {!ArrayBuffer} */ + buffer, /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ @@ -281,22 +1045,36 @@ var HEAP, /** @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); +function updateGlobalBufferAndViews(buf) { + buffer = buf; + Module['HEAP8'] = HEAP8 = new Int8Array(buf); + Module['HEAP16'] = HEAP16 = new Int16Array(buf); + Module['HEAP32'] = HEAP32 = new Int32Array(buf); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf); + Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf); + Module['HEAPF32'] = HEAPF32 = new Float32Array(buf); + Module['HEAPF64'] = HEAPF64 = new Float64Array(buf); } -// end include: runtime_shared.js + +var TOTAL_STACK = 5242880; + +var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 536870912; + +// include: runtime_init_table.js +// In regular non-RELOCATABLE mode the table is exported +// from the wasm module and this will be assigned once +// the exports are available. +var wasmTable; + +// end include: runtime_init_table.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 @@ -305,13 +1083,19 @@ var __ATPOSTRUN__ = []; // functions called after the main() is called var runtimeInitialized = false; +function keepRuntimeAlive() { + return noExitRuntime; +} + function preRun() { + if (Module['preRun']) { if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; while (Module['preRun'].length) { addOnPreRun(Module['preRun'].shift()); } } + callRuntimeCallbacks(__ATPRERUN__); } @@ -319,7 +1103,7 @@ function initRuntime() { runtimeInitialized = true; -if (!Module['noFSInit'] && !FS.init.initialized) +if (!Module["noFSInit"] && !FS.init.initialized) FS.init(); FS.ignorePermissions = false; @@ -355,6 +1139,8 @@ function addOnPostRun(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 @@ -382,14 +1168,18 @@ function getUniqueRunDependency(id) { function addRunDependency(id) { runDependencies++; - Module['monitorRunDependencies']?.(runDependencies); + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); + } } function removeRunDependency(id) { runDependencies--; - Module['monitorRunDependencies']?.(runDependencies); + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); + } if (runDependencies == 0) { if (runDependencyWatcher !== null) { @@ -406,7 +1196,11 @@ function removeRunDependency(id) { /** @param {string|number=} what */ function abort(what) { - Module['onAbort']?.(what); + { + if (Module['onAbort']) { + Module['onAbort'](what); + } + } what = 'Aborted(' + what + ')'; // TODO(sbc): Should we remove printing and leave it up to whoever @@ -428,7 +1222,7 @@ function abort(what) { // 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 + // 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} */ @@ -441,142 +1235,113 @@ function abort(what) { throw e; } +// {{MEM_INITIALIZER}} + // 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 a base64 data URI. +function isDataURI(filename) { + // Prefix of data URIs emitted by SINGLE_FILE and related options. + return 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 = 'basis_encoder.wasm'; - if (!isDataURI(f)) { - return locateFile(f); - } - return f; +// Indicates whether filename is delivered via file protocol (as opposed to http/https) +function isFileURI(filename) { + return filename.startsWith('file://'); } +// end include: URIUtils.js var wasmBinaryFile; - -function getBinarySync(file) { - if (file == wasmBinaryFile && wasmBinary) { - return new Uint8Array(wasmBinary); - } - if (readBinary) { - return readBinary(file); + wasmBinaryFile = 'basis_encoder.wasm'; + if (!isDataURI(wasmBinaryFile)) { + wasmBinaryFile = locateFile(wasmBinaryFile); } - 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) - ); +function getBinary(file) { + try { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } else { + throw "both async and sync fetching of the wasm failed"; + } + } + catch (err) { + abort(err); } - - // 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) && - // 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 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); +function getBinaryPromise() { + // If we don't have the binary yet, try to 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' + && !isFileURI(wasmBinaryFile) + ) { + 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(wasmBinaryFile); + }); + } + else { + if (readAsync) { + // fetch is not available or url is file => try XHR (readAsync uses XHR internally) + return new Promise(function(resolve, reject) { + readAsync(wasmBinaryFile, function(response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) }); - }); + } + } } - return instantiateArrayBuffer(binaryFile, imports, callback); -} -function getWasmImports() { - // prepare imports - return { - 'env': wasmImports, - 'wasi_snapshot_preview1': wasmImports, - } + // Otherwise, getBinary should be able to get it synchronously + return Promise.resolve().then(function() { return getBinary(wasmBinaryFile); }); } // Create the wasm instance. // Receives the wasm imports, returns the exports. function createWasm() { - var info = getWasmImports(); + // prepare imports + var info = { + 'env': asmLibraryArg, + 'wasi_snapshot_preview1': asmLibraryArg, + }; // 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; + var exports = instance.exports; - + Module['asm'] = exports; - wasmMemory = wasmExports['memory']; - - updateMemoryViews(); + wasmMemory = Module['asm']['memory']; + updateGlobalBufferAndViews(wasmMemory.buffer); - wasmTable = wasmExports['__indirect_function_table']; - + wasmTable = Module['asm']['__indirect_function_table']; - addOnInit(wasmExports['__wasm_call_ctors']); + addOnInit(Module['asm']['__wasm_call_ctors']); removeRunDependency('wasm-instantiate'); - return wasmExports; + } - // wait for the pthread pool (if any) + // we can't run yet (except in a pthread, where we have a custom sync instantiator) addRunDependency('wasm-instantiate'); // Prefer streaming instantiation if available. @@ -584,30 +1349,75 @@ function createWasm() { // '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. + // When the regression is fixed, can restore the above USE_PTHREADS-enabled path. receiveInstance(result['instance']); } + function instantiateArrayBuffer(receiver) { + return getBinaryPromise().then(function(binary) { + return WebAssembly.instantiate(binary, info); + }).then(function (instance) { + return instance; + }).then(receiver, function(reason) { + err('failed to asynchronously prepare wasm: ' + reason); + + abort(reason); + }); + } + + function instantiateAsync() { + if (!wasmBinary && + typeof WebAssembly.instantiateStreaming == 'function' && + !isDataURI(wasmBinaryFile) && + // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. + !isFileURI(wasmBinaryFile) && + // 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(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { + // Suppress closure warning here since the upstream definition for + // instantiateStreaming only allows Promise 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, info); + + return result.then( + receiveInstantiationResult, + 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(receiveInstantiationResult); + }); + }); + } else { + return instantiateArrayBuffer(receiveInstantiationResult); + } + } + // 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. + // 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); + var exports = Module['instantiateWasm'](info, receiveInstance); + return exports; } catch(e) { - err(`Module.instantiateWasm callback failed with error: ${e}`); - // If instantiation fails, reject the module ready promise. - readyPromiseReject(e); + err('Module.instantiateWasm callback failed with error: ' + e); + return false; } } - if (!wasmBinaryFile) wasmBinaryFile = findWasmBinary(); - // If instantiation fails, reject the module ready promise. - instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject); + instantiateAsync().catch(readyPromiseReject); return {}; // no exports yet; we'll fill them in later } @@ -615,47 +1425,120 @@ function createWasm() { var tempDouble; var tempI64; -// include: runtime_debug.js -// end include: runtime_debug.js // === Body === -// end include: preamble.js +var ASM_CONSTS = { + +}; - /** @constructor */ - function ExitStatus(status) { - this.name = 'ExitStatus'; - this.message = `Program terminated with exit(${status})`; - this.status = status; + + + + + + function callRuntimeCallbacks(callbacks) { + while (callbacks.length > 0) { + var callback = callbacks.shift(); + if (typeof callback == 'function') { + callback(Module); // Pass the module as the first argument. + continue; + } + var func = callback.func; + if (typeof func == 'number') { + if (callback.arg === undefined) { + // Run the wasm function ptr with signature 'v'. If no function + // with such signature was exported, this call does not need + // to be emitted (and would confuse Closure) + getWasmTableEntry(func)(); + } else { + // If any function with signature 'vi' was exported, run + // the callback with that signature. + getWasmTableEntry(func)(callback.arg); + } + } else { + func(callback.arg === undefined ? null : callback.arg); + } + } + } + + function withStackSave(f) { + var stack = stackSave(); + var ret = f(); + stackRestore(stack); + return ret; + } + function demangle(func) { + return func; + } + + function demangleAll(text) { + var regex = + /\b_Z[\w\d_]+/g; + return text.replace(regex, + function(x) { + var y = demangle(x); + return x === y ? x : (y + ' [' + x + ']'); + }); + } + + + /** + * @param {number} ptr + * @param {string} type + */ + function getValue(ptr, type = 'i8') { + if (type.endsWith('*')) type = 'i32'; + 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 HEAP32[((ptr)>>2)]; + case 'float': return HEAPF32[((ptr)>>2)]; + case 'double': return Number(HEAPF64[((ptr)>>3)]); + default: abort('invalid type for getValue: ' + type); + } + return null; + } + + var wasmTableMirror = []; + function getWasmTableEntry(funcPtr) { + var func = wasmTableMirror[funcPtr]; + if (!func) { + if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; + wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); + } + return func; } - var callRuntimeCallbacks = (callbacks) => { - while (callbacks.length > 0) { - // Pass the module as the first argument. - callbacks.shift()(Module); + function 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; } - }; - - - /** - * @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': abort('to do getValue(i64) use WASM_BIGINT'); - case 'float': return HEAPF32[((ptr)>>2)]; - case 'double': return HEAPF64[((ptr)>>3)]; - case '*': return HEAPU32[((ptr)>>2)]; - default: abort(`invalid type for getValue: ${type}`); + quit_(1, e); } - } - var noExitRuntime = Module['noExitRuntime'] || true; + function jsStackTrace() { + var error = new Error(); + if (!error.stack) { + // IE10+ special cases: It does have callstack info, but it is only + // populated if an Error object is thrown, so try that as a special-case. + try { + throw new Error(); + } catch(e) { + error = e; + } + if (!error.stack) { + return '(no stack trace available)'; + } + } + return error.stack.toString(); + } /** @@ -664,85 +1547,116 @@ var tempI64; * @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': abort('to do setValue(i64) use WASM_BIGINT'); - 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}`); + if (type.endsWith('*')) 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.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>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); + } + } + + function setWasmTableEntry(idx, func) { + wasmTable.set(idx, func); + // With ABORT_ON_WASM_EXCEPTIONS wasmTable.get is overriden to return wrapped + // functions so we need to call it here to retrieve the potential wrapper correctly + // instead of just storing 'func' directly into wasmTableMirror + wasmTableMirror[idx] = wasmTable.get(idx); } - } - var stackRestore = (val) => __emscripten_stack_restore(val); + function stackTrace() { + var js = jsStackTrace(); + if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace'](); + return demangleAll(js); + } - var stackSave = () => _emscripten_stack_get_current(); + function ___cxa_allocate_exception(size) { + // Thrown object is prepended by exception metadata block + return _malloc(size + 24) + 24; + } - class ExceptionInfo { - // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. - constructor(excPtr) { - this.excPtr = excPtr; - this.ptr = excPtr - 24; - } + /** @constructor */ + function ExceptionInfo(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - 24; - set_type(type) { + this.set_type = function(type) { HEAPU32[(((this.ptr)+(4))>>2)] = type; - } + }; - get_type() { + this.get_type = function() { return HEAPU32[(((this.ptr)+(4))>>2)]; - } + }; - set_destructor(destructor) { + this.set_destructor = function(destructor) { HEAPU32[(((this.ptr)+(8))>>2)] = destructor; - } + }; - get_destructor() { + this.get_destructor = function() { return HEAPU32[(((this.ptr)+(8))>>2)]; - } + }; - set_caught(caught) { + this.set_refcount = function(refcount) { + HEAP32[((this.ptr)>>2)] = refcount; + }; + + this.set_caught = function (caught) { caught = caught ? 1 : 0; - HEAP8[(this.ptr)+(12)] = caught; - } + HEAP8[(((this.ptr)+(12))>>0)] = caught; + }; - get_caught() { - return HEAP8[(this.ptr)+(12)] != 0; - } + this.get_caught = function () { + return HEAP8[(((this.ptr)+(12))>>0)] != 0; + }; - set_rethrown(rethrown) { + this.set_rethrown = function (rethrown) { rethrown = rethrown ? 1 : 0; - HEAP8[(this.ptr)+(13)] = rethrown; - } + HEAP8[(((this.ptr)+(13))>>0)] = rethrown; + }; - get_rethrown() { - return HEAP8[(this.ptr)+(13)] != 0; - } + this.get_rethrown = function () { + return HEAP8[(((this.ptr)+(13))>>0)] != 0; + }; // Initialize native structure fields. Should be called once after allocated. - init(type, destructor) { + this.init = function(type, destructor) { this.set_adjusted_ptr(0); this.set_type(type); this.set_destructor(destructor); + this.set_refcount(0); + this.set_caught(false); + this.set_rethrown(false); } - set_adjusted_ptr(adjustedPtr) { + this.add_ref = function() { + var value = HEAP32[((this.ptr)>>2)]; + HEAP32[((this.ptr)>>2)] = value + 1; + }; + + // Returns true if last reference released. + this.release_ref = function() { + var prev = HEAP32[((this.ptr)>>2)]; + HEAP32[((this.ptr)>>2)] = prev - 1; + return prev === 1; + }; + + this.set_adjusted_ptr = function(adjustedPtr) { HEAPU32[(((this.ptr)+(16))>>2)] = adjustedPtr; - } + }; - get_adjusted_ptr() { + this.get_adjusted_ptr = function() { return HEAPU32[(((this.ptr)+(16))>>2)]; - } + }; // Get pointer which is expected to be received by catch clause in C++ code. It may be adjusted // when the pointer is casted to some of the exception object base classes (e.g. when virtual // inheritance is used). When a pointer is thrown this method should return the thrown pointer // itself. - get_exception_ptr() { + this.get_exception_ptr = function() { // Work around a fastcomp bug, this code is still included for some reason in a build without // exceptions support. var isPointer = ___cxa_is_pointer_type(this.get_type()); @@ -752,38 +1666,30 @@ var tempI64; var adjusted = this.get_adjusted_ptr(); if (adjusted !== 0) return adjusted; return this.excPtr; - } + }; } var exceptionLast = 0; var uncaughtExceptionCount = 0; - var ___cxa_throw = (ptr, type, destructor) => { + function ___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; - }; + throw ptr; + } - /** @suppress {duplicate } */ - function 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; + function setErrNo(value) { + HEAP32[((___errno_location())>>2)] = value; + return value; } - var syscallGetVarargP = syscallGetVarargI; - - var PATH = { - isAbs:(path) => path.charAt(0) === '/', - splitPath:(filename) => { + var PATH = {isAbs:(path) => path.charAt(0) === '/',splitPath:(filename) => { var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; return splitPathRe.exec(filename).slice(1); - }, - normalizeArray:(parts, allowAboveRoot) => { + },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--) { @@ -805,8 +1711,7 @@ var tempI64; } } return parts; - }, - normalize:(path) => { + },normalize:(path) => { var isAbsolute = PATH.isAbs(path), trailingSlash = path.substr(-1) === '/'; // Normalize the path @@ -818,8 +1723,7 @@ var tempI64; path += '/'; } return (isAbsolute ? '/' : '') + path; - }, - dirname:(path) => { + },dirname:(path) => { var result = PATH.splitPath(path), root = result[0], dir = result[1]; @@ -832,8 +1736,7 @@ var tempI64; dir = dir.substr(0, dir.length - 1); } return root + dir; - }, - basename:(path) => { + },basename:(path) => { // EMSCRIPTEN return '/'' for '/', not an empty string if (path === '/') return '/'; path = PATH.normalize(path); @@ -841,52 +1744,38 @@ var tempI64; 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 = () => { + },join:function() { + var paths = Array.prototype.slice.call(arguments, 0); + return PATH.normalize(paths.join('/')); + },join2:(l, r) => { + return PATH.normalize(l + '/' + r); + }}; + + function getRandomDevice() { if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') { // for modern web browsers - return (view) => crypto.getRandomValues(view); + var randomBuffer = new Uint8Array(1); + return function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; } 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 - ); + // nodejs has crypto support + return function() { return crypto_module['randomBytes'](1)[0]; }; } catch (e) { // nodejs doesn't have crypto support } } // 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); - }; - - + return function() { abort("randomDevice"); }; + } - var PATH_FS = { - resolve:(...args) => { + var PATH_FS = {resolve:function() { var resolvedPath = '', resolvedAbsolute = false; - for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? args[i] : FS.cwd(); + 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'); @@ -900,8 +1789,7 @@ var tempI64; // 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) => { + },relative:(from, to) => { from = PATH_FS.resolve(from).substr(1); to = PATH_FS.resolve(to).substr(1); function trim(arr) { @@ -932,200 +1820,18 @@ var tempI64; } 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, 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 (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() { + var TTY = {ttys:[],init:function () { // 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'); + // process['stdin']['setEncoding']('utf8'); // } - }, - shutdown() { + },shutdown:function() { // 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)? @@ -1133,30 +1839,24 @@ var tempI64; // // 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(); + // process['stdin']['pause'](); // } - }, - register(dev, ops) { + },register:function(dev, ops) { TTY.ttys[dev] = { input: [], output: [], ops: ops }; FS.registerDevice(dev, TTY.stream_ops); - }, - stream_ops:{ - open(stream) { + },stream_ops:{open:function(stream) { var tty = TTY.ttys[stream.node.rdev]; if (!tty) { throw new FS.ErrnoError(43); } stream.tty = tty; stream.seekable = false; - }, - close(stream) { + },close:function(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 */) { + stream.tty.ops.flush(stream.tty); + },flush:function(stream) { + stream.tty.ops.flush(stream.tty); + },read:function(stream, buffer, offset, length, pos /* ignored */) { if (!stream.tty || !stream.tty.ops.get_char) { throw new FS.ErrnoError(60); } @@ -1179,8 +1879,7 @@ var tempI64; stream.node.timestamp = Date.now(); } return bytesRead; - }, - write(stream, buffer, offset, length, pos) { + },write:function(stream, buffer, offset, length, pos) { if (!stream.tty || !stream.tty.ops.put_char) { throw new FS.ErrnoError(60); } @@ -1195,138 +1894,146 @@ var tempI64; stream.node.timestamp = Date.now(); } return i; - }, - }, - default_tty_ops:{ - get_char(tty) { - return FS_stdin_getChar(); - }, - put_char(tty, val) { + }},default_tty_ops:{get_char:function(tty) { + if (!tty.input.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; + + try { + bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1); + } 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 { + result = null; + } + } 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) { 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) { + },flush:function(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) { + }},default_tty1_ops:{put_char:function(tty, val) { if (val === null || val === 10) { err(UTF8ArrayToString(tty.output, 0)); tty.output = []; } else { if (val != 0) tty.output.push(val); } - }, - fsync(tty) { + },flush:function(tty) { if (tty.output && tty.output.length > 0) { err(UTF8ArrayToString(tty.output, 0)); tty.output = []; } - }, - }, - }; - + }}}; - var zeroMemory = (address, size) => { + function zeroMemory(address, size) { HEAPU8.fill(0, address, address + size); - return address; - }; + } - var alignMemory = (size, alignment) => { + function alignMemory(size, alignment) { return Math.ceil(size / alignment) * alignment; - }; - var mmapAlloc = (size) => { + } + function 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) { + zeroMemory(ptr, size); + return ptr; + } + var MEMFS = {ops_table:null,mount:function(mount) { return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0); - }, - createNode(parent, name, mode, dev) { + },createNode:function(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 + 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 + } }, - 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 + 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 + } }, - stream: {} - }, - chrdev: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink + }, + stream: {} }, - stream: FS.chrdev_stream_ops - } - }; + 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; @@ -1354,13 +2061,11 @@ var tempI64; parent.timestamp = node.timestamp; } return node; - }, - getFileDataAsTypedArray(node) { + },getFileDataAsTypedArray:function(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) { + },expandFileStorage:function(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. @@ -1372,8 +2077,7 @@ var tempI64; 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) { + },resizeFileStorage:function(node, newSize) { if (node.usedBytes == newSize) return; if (newSize == 0) { node.contents = null; // Fully decommit when requesting a resize to zero. @@ -1386,9 +2090,7 @@ var tempI64; } node.usedBytes = newSize; } - }, - node_ops:{ - getattr(node) { + },node_ops:{getattr:function(node) { var attr = {}; // device numbers reuse inode numbers. attr.dev = FS.isChrdev(node.mode) ? node.id : 1; @@ -1415,8 +2117,7 @@ var tempI64; attr.blksize = 4096; attr.blocks = Math.ceil(attr.size / attr.blksize); return attr; - }, - setattr(node, attr) { + },setattr:function(node, attr) { if (attr.mode !== undefined) { node.mode = attr.mode; } @@ -1426,14 +2127,11 @@ var tempI64; if (attr.size !== undefined) { MEMFS.resizeFileStorage(node, attr.size); } - }, - lookup(parent, name) { + },lookup:function(parent, name) { throw FS.genericErrors[44]; - }, - mknod(parent, name, mode, dev) { + },mknod:function(parent, name, mode, dev) { return MEMFS.createNode(parent, name, mode, dev); - }, - rename(old_node, new_dir, new_name) { + },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; @@ -1453,40 +2151,36 @@ var tempI64; old_node.name = new_name; new_dir.contents[new_name] = old_node; new_dir.timestamp = old_node.parent.timestamp; - }, - unlink(parent, name) { + old_node.parent = new_dir; + },unlink:function(parent, name) { delete parent.contents[name]; parent.timestamp = Date.now(); - }, - rmdir(parent, name) { + },rmdir:function(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) { + },readdir:function(node) { var entries = ['.', '..']; - for (var key of Object.keys(node.contents)) { + for (var key in node.contents) { + if (!node.contents.hasOwnProperty(key)) { + continue; + } entries.push(key); } return entries; - }, - symlink(parent, newname, oldpath) { + },symlink:function(parent, newname, oldpath) { var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0); node.link = oldpath; return node; - }, - readlink(node) { + },readlink:function(node) { if (!FS.isLink(node.mode)) { throw new FS.ErrnoError(28); } return node.link; - }, - }, - stream_ops:{ - read(stream, buffer, offset, length, position) { + }},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); @@ -1496,8 +2190,7 @@ var tempI64; for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]; } return size; - }, - write(stream, buffer, offset, length, position, canOwn) { + },write:function(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 @@ -1537,8 +2230,7 @@ var tempI64; } node.usedBytes = Math.max(node.usedBytes, position + length); return length; - }, - llseek(stream, offset, whence) { + },llseek:function(stream, offset, whence) { var position = offset; if (whence === 1) { position += stream.position; @@ -1551,12 +2243,10 @@ var tempI64; throw new FS.ErrnoError(28); } return position; - }, - allocate(stream, offset, length) { + },allocate:function(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) { + },mmap:function(stream, length, position, prot, flags) { if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError(43); } @@ -1564,9 +2254,9 @@ var tempI64; var allocated; var contents = stream.node.contents; // Only make a new copy when MAP_PRIVATE is specified. - if (!(flags & 2) && 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). + if (!(flags & 2) && contents.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 { @@ -1585,211 +2275,39 @@ var tempI64; } HEAP8.set(contents, ptr); } - return { ptr, allocated }; - }, - msync(stream, buffer, offset, length, mmapFlags) { - MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); + return { ptr: ptr, allocated: allocated }; + },msync:function(stream, buffer, offset, length, mmapFlags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (mmapFlags & 2) { + // MAP_PRIVATE calls need not to be synced back to underlying fs + return 0; + } + + var bytesWritten = 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; + function asyncLoad(url, onload, onerror, noRunDep) { + var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''; + readAsync(url, function(arrayBuffer) { + assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).'); + onload(new Uint8Array(arrayBuffer)); + if (dep) removeRunDependency(dep); + }, function(event) { + if (onerror) { + onerror(); + } else { + throw 'Loading data file "' + url + '" failed.'; } }); - 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 { - // 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) { - // TODO(sbc): Use the inline member declaration syntax once we - // support it in acorn and closure. - this.name = 'ErrnoError'; - this.errno = errno; - } - }, - genericErrors:{ - }, - filesystems:null, - syncFSRequests:0, - FSStream:class { - constructor() { - // TODO(https://github.com/emscripten-core/emscripten/issues/21414): - // Use inline field declarations. - this.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 { - constructor(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; - this.readMode = 292/*292*/ | 73/*73*/; - this.writeMode = 146/*146*/; - } - 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 (dep) addRunDependency(dep); + } + var FS = {root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path, opts = {}) => { + path = PATH_FS.resolve(FS.cwd(), path); if (!path) return { path: '', node: null }; @@ -1803,8 +2321,8 @@ var tempI64; throw new FS.ErrnoError(32); } - // split the absolute path - var parts = path.split('/').filter((p) => !!p); + // split the path + var parts = PATH.normalizeArray(path.split('/').filter((p) => !!p), false); // start at the root var current = FS.root; @@ -1846,33 +2364,29 @@ var tempI64; } return { path: current_path, node: current }; - }, - getPath(node) { + },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; + return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path; } - path = path ? `${node.name}/${path}` : node.name; + path = path ? node.name + '/' + path : node.name; node = node.parent; } - }, - hashName(parentid, name) { + },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) { + },hashAddNode:(node) => { var hash = FS.hashName(node.parent.id, node.name); node.name_next = FS.nameTable[hash]; FS.nameTable[hash] = node; - }, - hashRemoveNode(node) { + },hashRemoveNode:(node) => { var hash = FS.hashName(node.parent.id, node.name); if (FS.nameTable[hash] === node) { FS.nameTable[hash] = node.name_next; @@ -1886,11 +2400,10 @@ var tempI64; current = current.name_next; } } - }, - lookupNode(parent, name) { + },lookupNode:(parent, name) => { var errCode = FS.mayLookup(parent); if (errCode) { - throw new FS.ErrnoError(errCode); + throw new FS.ErrnoError(errCode, parent); } var hash = FS.hashName(parent.id, name); for (var node = FS.nameTable[hash]; node; node = node.name_next) { @@ -1901,52 +2414,45 @@ var tempI64; } // if we failed to find it in the cache, call into the VFS return FS.lookup(parent, name); - }, - createNode(parent, name, mode, rdev) { + },createNode:(parent, name, mode, rdev) => { var node = new FS.FSNode(parent, name, mode, rdev); FS.hashAddNode(node); return node; - }, - destroyNode(node) { + },destroyNode:(node) => { FS.hashRemoveNode(node); - }, - isRoot(node) { + },isRoot:(node) => { return node === node.parent; - }, - isMountpoint(node) { + },isMountpoint:(node) => { return !!node.mounted; - }, - isFile(mode) { + },isFile:(mode) => { return (mode & 61440) === 32768; - }, - isDir(mode) { + },isDir:(mode) => { return (mode & 61440) === 16384; - }, - isLink(mode) { + },isLink:(mode) => { return (mode & 61440) === 40960; - }, - isChrdev(mode) { + },isChrdev:(mode) => { return (mode & 61440) === 8192; - }, - isBlkdev(mode) { + },isBlkdev:(mode) => { return (mode & 61440) === 24576; - }, - isFIFO(mode) { + },isFIFO:(mode) => { return (mode & 61440) === 4096; - }, - isSocket(mode) { + },isSocket:(mode) => { return (mode & 49152) === 49152; - }, - flagsToPermissionString(flag) { + },flagModes:{"r":0,"r+":2,"w":577,"w+":578,"a":1089,"a+":1090},modeStringToFlags:(str) => { + var flags = FS.flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error('Unknown file open mode: ' + str); + } + return flags; + },flagsToPermissionString:(flag) => { var perms = ['r', 'w', 'rw'][flag & 3]; if ((flag & 512)) { perms += 'w'; } return perms; - }, - nodePermissions(node, perms) { + },nodePermissions:(node, perms) => { if (FS.ignorePermissions) { return 0; } @@ -1959,23 +2465,19 @@ var tempI64; return 2; } return 0; - }, - mayLookup(dir) { - if (!FS.isDir(dir.mode)) return 54; + },mayLookup:(dir) => { var errCode = FS.nodePermissions(dir, 'x'); if (errCode) return errCode; if (!dir.node_ops.lookup) return 2; return 0; - }, - mayCreate(dir, name) { + },mayCreate:(dir, name) => { try { var node = FS.lookupNode(dir, name); return 20; } catch (e) { } return FS.nodePermissions(dir, 'wx'); - }, - mayDelete(dir, name, isdir) { + },mayDelete:(dir, name, isdir) => { var node; try { node = FS.lookupNode(dir, name); @@ -1999,8 +2501,7 @@ var tempI64; } } return 0; - }, - mayOpen(node, flags) { + },mayOpen:(node, flags) => { if (!node) { return 44; } @@ -2013,63 +2514,63 @@ var tempI64; } } return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); - }, - MAX_OPEN_FDS:4096, - nextfd() { - for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { + },MAX_OPEN_FDS:4096,nextfd:(fd_start = 0, 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(33); - }, - getStreamChecked(fd) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); + },getStream:(fd) => FS.streams[fd],createStream:(stream, fd_start, fd_end) => { + if (!FS.FSStream) { + FS.FSStream = /** @constructor */ function() { + this.shared = { }; + }; + 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); } + }, + flags: { + get: function() { return this.shared.flags; }, + set: function(val) { this.shared.flags = val; }, + }, + position : { + get function() { return this.shared.position; }, + set: function(val) { this.shared.position = val; }, + }, + }; } - 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(); - } + var fd = FS.nextfd(fd_start, fd_end); stream.fd = fd; FS.streams[fd] = stream; return stream; - }, - closeStream(fd) { + },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) { + },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() { + if (stream.stream_ops.open) { + 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) { + }},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) { + },getDevice:(dev) => FS.devices[dev],getMounts:(mount) => { var mounts = []; var check = [mount]; @@ -2078,12 +2579,11 @@ var tempI64; mounts.push(m); - check.push(...m.mounts); + check.push.apply(check, m.mounts); } return mounts; - }, - syncfs(populate, callback) { + },syncfs:(populate, callback) => { if (typeof populate == 'function') { callback = populate; populate = false; @@ -2092,7 +2592,7 @@ var tempI64; FS.syncFSRequests++; if (FS.syncFSRequests > 1) { - err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); + err('warning: ' + FS.syncFSRequests + ' FS.syncfs operations in flight at once, probably just doing extra work'); } var mounts = FS.getMounts(FS.root.mount); @@ -2123,8 +2623,7 @@ var tempI64; } mount.type.syncfs(mount, populate, done); }); - }, - mount(type, opts, mountpoint) { + },mount:(type, opts, mountpoint) => { var root = mountpoint === '/'; var pseudo = !mountpoint; var node; @@ -2147,9 +2646,9 @@ var tempI64; } var mount = { - type, - opts, - mountpoint, + type: type, + opts: opts, + mountpoint: mountpoint, mounts: [] }; @@ -2171,8 +2670,7 @@ var tempI64; } return mountRoot; - }, - unmount(mountpoint) { + },unmount:(mountpoint) => { var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); if (!FS.isMountpoint(lookup.node)) { @@ -2204,11 +2702,9 @@ var tempI64; // remove this mount from the child mounts var idx = node.mount.mounts.indexOf(mount); node.mount.mounts.splice(idx, 1); - }, - lookup(parent, name) { + },lookup:(parent, name) => { return parent.node_ops.lookup(parent, name); - }, - mknod(path, mode, dev) { + },mknod:(path, mode, dev) => { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); @@ -2223,20 +2719,17 @@ var tempI64; throw new FS.ErrnoError(63); } return parent.node_ops.mknod(parent, name, mode, dev); - }, - create(path, mode) { + },create:(path, mode) => { mode = mode !== undefined ? mode : 438 /* 0666 */; mode &= 4095; mode |= 32768; return FS.mknod(path, mode, 0); - }, - mkdir(path, mode) { + },mkdir:(path, mode) => { mode = mode !== undefined ? mode : 511 /* 0777 */; mode &= 511 | 512; mode |= 16384; return FS.mknod(path, mode, 0); - }, - mkdirTree(path, mode) { + },mkdirTree:(path, mode) => { var dirs = path.split('/'); var d = ''; for (var i = 0; i < dirs.length; ++i) { @@ -2248,16 +2741,14 @@ var tempI64; if (e.errno != 20) throw e; } } - }, - mkdev(path, mode, dev) { + },mkdev:(path, mode, dev) => { if (typeof dev == 'undefined') { dev = mode; mode = 438 /* 0666 */; } mode |= 8192; return FS.mknod(path, mode, dev); - }, - symlink(oldpath, newpath) { + },symlink:(oldpath, newpath) => { if (!PATH_FS.resolve(oldpath)) { throw new FS.ErrnoError(44); } @@ -2275,8 +2766,7 @@ var tempI64; throw new FS.ErrnoError(63); } return parent.node_ops.symlink(parent, newname, oldpath); - }, - rename(old_path, new_path) { + },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); @@ -2284,7 +2774,7 @@ var tempI64; // parents must exist var lookup, old_dir, new_dir; - // let the errors from non existent directories percolate up + // let the errors from non existant directories percolate up lookup = FS.lookupPath(old_path, { parent: true }); old_dir = lookup.node; lookup = FS.lookupPath(new_path, { parent: true }); @@ -2350,9 +2840,6 @@ var tempI64; // 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 { @@ -2360,8 +2847,7 @@ var tempI64; // changed its name) FS.hashAddNode(old_node); } - }, - rmdir(path) { + },rmdir:(path) => { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); @@ -2378,16 +2864,14 @@ var tempI64; } parent.node_ops.rmdir(parent, name); FS.destroyNode(node); - }, - readdir(path) { + },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) { + },unlink:(path) => { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; if (!parent) { @@ -2410,8 +2894,7 @@ var tempI64; } parent.node_ops.unlink(parent, name); FS.destroyNode(node); - }, - readlink(path) { + },readlink:(path) => { var lookup = FS.lookupPath(path); var link = lookup.node; if (!link) { @@ -2421,8 +2904,7 @@ var tempI64; throw new FS.ErrnoError(28); } return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); - }, - stat(path, dontFollow) { + },stat:(path, dontFollow) => { var lookup = FS.lookupPath(path, { follow: !dontFollow }); var node = lookup.node; if (!node) { @@ -2432,11 +2914,9 @@ var tempI64; throw new FS.ErrnoError(63); } return node.node_ops.getattr(node); - }, - lstat(path) { + },lstat:(path) => { return FS.stat(path, true); - }, - chmod(path, mode, dontFollow) { + },chmod:(path, mode, dontFollow) => { var node; if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: !dontFollow }); @@ -2451,15 +2931,15 @@ var tempI64; mode: (mode & 4095) | (node.mode & ~4095), timestamp: Date.now() }); - }, - lchmod(path, mode) { + },lchmod:(path, mode) => { FS.chmod(path, mode, true); - }, - fchmod(fd, mode) { - var stream = FS.getStreamChecked(fd); + },fchmod:(fd, mode) => { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } FS.chmod(stream.node, mode); - }, - chown(path, uid, gid, dontFollow) { + },chown:(path, uid, gid, dontFollow) => { var node; if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: !dontFollow }); @@ -2474,15 +2954,15 @@ var tempI64; timestamp: Date.now() // we ignore the uid / gid for now }); - }, - lchown(path, uid, gid) { + },lchown:(path, uid, gid) => { FS.chown(path, uid, gid, true); - }, - fchown(fd, uid, gid) { - var stream = FS.getStreamChecked(fd); + },fchown:(fd, uid, gid) => { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } FS.chown(stream.node, uid, gid); - }, - truncate(path, len) { + },truncate:(path, len) => { if (len < 0) { throw new FS.ErrnoError(28); } @@ -2510,28 +2990,28 @@ var tempI64; size: len, timestamp: Date.now() }); - }, - ftruncate(fd, len) { - var stream = FS.getStreamChecked(fd); + },ftruncate:(fd, len) => { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } if ((stream.flags & 2097155) === 0) { throw new FS.ErrnoError(28); } FS.truncate(stream.node, len); - }, - utime(path, atime, mtime) { + },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) { + },open:(path, flags, mode) => { if (path === "") { throw new FS.ErrnoError(44); } - flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; + flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; if ((flags & 64)) { - mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; mode = (mode & 4095) | 32768; } else { mode = 0; @@ -2593,9 +3073,9 @@ var tempI64; // register the stream with the filesystem var stream = FS.createStream({ - node, + node: node, path: FS.getPath(node), // we want the absolute path to the node - flags, + flags: flags, seekable: true, position: 0, stream_ops: node.stream_ops, @@ -2614,8 +3094,7 @@ var tempI64; } } return stream; - }, - close(stream) { + },close:(stream) => { if (FS.isClosed(stream)) { throw new FS.ErrnoError(8); } @@ -2630,11 +3109,9 @@ var tempI64; FS.closeStream(stream.fd); } stream.fd = null; - }, - isClosed(stream) { + },isClosed:(stream) => { return stream.fd === null; - }, - llseek(stream, offset, whence) { + },llseek:(stream, offset, whence) => { if (FS.isClosed(stream)) { throw new FS.ErrnoError(8); } @@ -2647,8 +3124,7 @@ var tempI64; stream.position = stream.stream_ops.llseek(stream, offset, whence); stream.ungotten = []; return stream.position; - }, - read(stream, buffer, offset, length, position) { + },read:(stream, buffer, offset, length, position) => { if (length < 0 || position < 0) { throw new FS.ErrnoError(28); } @@ -2673,8 +3149,7 @@ var tempI64; 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) { + },write:(stream, buffer, offset, length, position, canOwn) => { if (length < 0 || position < 0) { throw new FS.ErrnoError(28); } @@ -2703,8 +3178,7 @@ var tempI64; var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); if (!seeking) stream.position += bytesWritten; return bytesWritten; - }, - allocate(stream, offset, length) { + },allocate:(stream, offset, length) => { if (FS.isClosed(stream)) { throw new FS.ErrnoError(8); } @@ -2721,8 +3195,7 @@ var tempI64; throw new FS.ErrnoError(138); } stream.stream_ops.allocate(stream, offset, length); - }, - mmap(stream, length, position, prot, flags) { + },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 @@ -2741,24 +3214,21 @@ var tempI64; throw new FS.ErrnoError(43); } return stream.stream_ops.mmap(stream, length, position, prot, flags); - }, - msync(stream, buffer, offset, length, mmapFlags) { - if (!stream.stream_ops.msync) { + },msync:(stream, buffer, offset, length, mmapFlags) => { + if (!stream || !stream.stream_ops.msync) { return 0; } return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); - }, - ioctl(stream, cmd, arg) { + },munmap:(stream) => 0,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 = {}) { + },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}"`); + throw new Error('Invalid encoding type "' + opts.encoding + '"'); } var ret; var stream = FS.open(path, opts.flags); @@ -2773,8 +3243,7 @@ var tempI64; } FS.close(stream); return ret; - }, - writeFile(path, data, opts = {}) { + },writeFile:(path, data, opts = {}) => { opts.flags = opts.flags || 577; var stream = FS.open(path, opts.flags, opts.mode); if (typeof data == 'string') { @@ -2787,9 +3256,7 @@ var tempI64; throw new Error('Unsupported data type'); } FS.close(stream); - }, - cwd:() => FS.currentPath, - chdir(path) { + },cwd:() => FS.currentPath,chdir:(path) => { var lookup = FS.lookupPath(path, { follow: true }); if (lookup.node === null) { throw new FS.ErrnoError(44); @@ -2802,13 +3269,11 @@ var tempI64; throw new FS.ErrnoError(errCode); } FS.currentPath = lookup.path; - }, - createDefaultDirectories() { + },createDefaultDirectories:() => { FS.mkdir('/tmp'); FS.mkdir('/home'); FS.mkdir('/home/web_user'); - }, - createDefaultDevices() { + },createDefaultDevices:() => { // create /dev FS.mkdir('/dev'); // setup /dev/null @@ -2825,34 +3290,27 @@ var tempI64; 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); + var random_device = getRandomDevice(); + FS.createDevice('/dev', 'random', random_device); + FS.createDevice('/dev', 'urandom', random_device); // 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() { + },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() { + mount: () => { var node = FS.createNode(proc_self, 'fd', 16384 | 511 /* 0777 */, 73); node.node_ops = { - lookup(parent, name) { + lookup: (parent, name) => { var fd = +name; - var stream = FS.getStreamChecked(fd); + var stream = FS.getStream(fd); + if (!stream) throw new FS.ErrnoError(8); var ret = { parent: null, mount: { mountpoint: 'fake' }, @@ -2865,8 +3323,7 @@ var tempI64; return node; } }, {}, '/proc/self/fd'); - }, - createStandardStreams() { + },createStandardStreams:() => { // 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 @@ -2895,13 +3352,26 @@ var tempI64; var stdin = FS.open('/dev/stdin', 0); var stdout = FS.open('/dev/stdout', 1); var stderr = FS.open('/dev/stderr', 1); - }, - staticInit() { + },ensureErrnoError:() => { + if (FS.ErrnoError) return; + FS.ErrnoError = /** @this{Object} */ function ErrnoError(errno, node) { + this.node = node; + this.setErrno = /** @this{Object} */ function(errno) { + this.errno = errno; + }; + this.setErrno(errno); + this.message = 'FS error'; + + }; + 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) [44].forEach((code) => { FS.genericErrors[code] = new FS.ErrnoError(code); FS.genericErrors[code].stack = ''; }); + },staticInit:() => { + FS.ensureErrnoError(); FS.nameTable = new Array(4096); @@ -2914,18 +3384,18 @@ var tempI64; FS.filesystems = { 'MEMFS': MEMFS, }; - }, - init(input, output, error) { + },init:(input, output, error) => { 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() { + },quit:() => { FS.init.initialized = false; // force-flush all streams, so we get musl std streams printed out // close all of our streams @@ -2936,15 +3406,19 @@ var tempI64; } FS.close(stream); } - }, - findObject(path, dontResolveLastLink) { + },getMode:(canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; + },findObject:(path, dontResolveLastLink) => { var ret = FS.analyzePath(path, dontResolveLastLink); - if (!ret.exists) { + if (ret.exists) { + return ret.object; + } else { return null; } - return ret.object; - }, - analyzePath(path, dontResolveLastLink) { + },analyzePath:(path, dontResolveLastLink) => { // operate from within the context of the symlink's target try { var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); @@ -2971,8 +3445,7 @@ var tempI64; ret.error = e.errno; }; return ret; - }, - createPath(parent, path, canRead, canWrite) { + },createPath:(parent, path, canRead, canWrite) => { parent = typeof parent == 'string' ? parent : FS.getPath(parent); var parts = path.split('/').reverse(); while (parts.length) { @@ -2987,19 +3460,17 @@ var tempI64; parent = current; } return current; - }, - createFile(parent, name, properties, canRead, canWrite) { + },createFile:(parent, name, properties, canRead, canWrite) => { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); - var mode = FS_getMode(canRead, canWrite); + var mode = FS.getMode(canRead, canWrite); return FS.create(path, mode); - }, - createDataFile(parent, name, data, canRead, canWrite, canOwn) { + },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 mode = FS.getMode(canRead, canWrite); var node = FS.create(path, mode); if (data) { if (typeof data == 'string') { @@ -3014,25 +3485,25 @@ var tempI64; FS.close(stream); FS.chmod(node, mode); } - }, - createDevice(parent, name, input, output) { + return node; + },createDevice:(parent, name, input, output) => { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); - var mode = FS_getMode(!!input, !!output); + 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(stream) { + open: (stream) => { stream.seekable = false; }, - close(stream) { + close: (stream) => { // flush any pending line data - if (output?.buffer?.length) { + if (output && output.buffer && output.buffer.length) { output(10); } }, - read(stream, buffer, offset, length, pos /* ignored */) { + read: (stream, buffer, offset, length, pos /* ignored */) => { var bytesRead = 0; for (var i = 0; i < length; i++) { var result; @@ -3053,7 +3524,7 @@ var tempI64; } return bytesRead; }, - write(stream, buffer, offset, length, pos) { + write: (stream, buffer, offset, length, pos) => { for (var i = 0; i < length; i++) { try { output(buffer[offset+i]); @@ -3068,118 +3539,126 @@ var tempI64; } }); return FS.mkdev(path, mode, dev); - }, - forceLoadFile(obj) { + },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. + } else if (read_) { + // Command-line. try { - obj.contents = readBinary(obj.url); + // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as + // read() will try to parse UTF8. + obj.contents = intArrayFromString(read_(obj.url), true); 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 { - constructor() { - this.lengthKnown = false; - this.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; + } else { + throw new Error('Cannot load without read() or XMLHttpRequest.'); + } + },createLazyFile:(parent, name, url, canRead, canWrite) => { + // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse. + /** @constructor */ + function LazyUint8Array() { + this.lengthKnown = false; + this.chunks = []; // Loaded chunks. Index is the chunk number + } + LazyUint8Array.prototype.get = /** @this{Object} */ function LazyUint8Array_get(idx) { + if (idx > this.length-1 || idx < 0) { + return undefined; } - cacheLength() { - // Find length + 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() { + // 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('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} */(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]; - }); + xhr.open('GET', url, false); + if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); - 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"); + // Some hints to the browser that we want binary data. + xhr.responseType = 'arraybuffer'; + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain; charset=x-user-defined'); } - this._length = datalength; - this._chunkSize = chunkSize; - this.lengthKnown = true; - } - get length() { - if (!this.lengthKnown) { - this.cacheLength(); + 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} */(xhr.response || [])); + } else { + return intArrayFromString(xhr.responseText || '', true); } - return this._length; - } - get chunkSize() { - if (!this.lengthKnown) { - this.cacheLength(); + }; + 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); } - return this._chunkSize; + 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; + }; 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: /** @this{Object} */ function() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } + }, + chunkSize: { + get: /** @this{Object} */ function() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } + } + }); + var properties = { isDevice: false, contents: lazyArray }; } else { var properties = { isDevice: false, url: url }; @@ -3198,7 +3677,7 @@ var tempI64; // 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; } + get: /** @this {FSNode} */ function() { return this.contents.length; } } }); // override each stream op with one that tries to force load the lazy file first @@ -3206,9 +3685,9 @@ var tempI64; var keys = Object.keys(node.stream_ops); keys.forEach((key) => { var fn = node.stream_ops[key]; - stream_ops[key] = (...args) => { + stream_ops[key] = function forceLoadLazyFile() { FS.forceLoadFile(node); - return fn(...args); + return fn.apply(null, arguments); }; }); function writeChunks(stream, buffer, offset, length, position) { @@ -3240,35 +3719,112 @@ var tempI64; throw new FS.ErrnoError(48); } writeChunks(stream, HEAP8, ptr, length, position); - return { ptr, allocated: true }; + return { ptr: 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) => { - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; - }; - var SYSCALLS = { - DEFAULT_POLLMASK:5, - calculateAt(dirfd, path, allowEmpty) { + },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) { + if (preFinish) preFinish(); + if (!dontCreateFile) { + FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + if (onload) onload(); + removeRunDependency(dep); + } + if (Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { + if (onerror) onerror(); + removeRunDependency(dep); + })) { + return; + } + finish(byteArray); + } + addRunDependency(dep); + if (typeof url == 'string') { + asyncLoad(url, (byteArray) => processData(byteArray), onerror); + } else { + processData(url); + } + },indexedDB:() => { + return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; + },DB_NAME:() => { + return 'EM_FS_' + window.location.pathname; + },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:(paths, onload, onerror) => { + onload = onload || (() => {}); + onerror = onerror || (() => {}); + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = () => { + out('creating db'); + var db = openRequest.result; + db.createObjectStore(FS.DB_STORE_NAME); + }; + 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((path) => { + var putRequest = files.put(FS.analyzePath(path).object.contents, path); + putRequest.onsuccess = () => { ok++; if (ok + fail == total) finish() }; + putRequest.onerror = () => { fail++; if (ok + fail == total) finish() }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + },loadFilesFromDB:(paths, onload, onerror) => { + onload = onload || (() => {}); + onerror = onerror || (() => {}); + 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 = () => { + 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((path) => { + var getRequest = files.get(path); + 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 = () => { fail++; if (ok + fail == total) finish() }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + }}; + var SYSCALLS = {DEFAULT_POLLMASK:5,calculateAt:function(dirfd, path, allowEmpty) { if (PATH.isAbs(path)) { return path; } @@ -3277,7 +3833,8 @@ var tempI64; if (dirfd === -100) { dir = FS.cwd(); } else { - var dirstream = SYSCALLS.getStreamFromFD(dirfd); + var dirstream = FS.getStream(dirfd); + if (!dirstream) throw new FS.ErrnoError(8); dir = dirstream.path; } if (path.length == 0) { @@ -3287,51 +3844,51 @@ var tempI64; return dir; } return PATH.join2(dir, path); - }, - doStat(func, path, buf) { - var stat = func(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))) { + // an error occurred while trying to look up the path; we should just report ENOTDIR + return -54; + } + throw e; + } 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.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>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 / 1000)>>>0,(tempDouble = Math.floor(atime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(40))>>2)] = tempI64[0],HEAP32[(((buf)+(44))>>2)] = tempI64[1]); - HEAPU32[(((buf)+(48))>>2)] = (atime % 1000) * 1000; - (tempI64 = [Math.floor(mtime / 1000)>>>0,(tempDouble = Math.floor(mtime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(56))>>2)] = tempI64[0],HEAP32[(((buf)+(60))>>2)] = tempI64[1]); - HEAPU32[(((buf)+(64))>>2)] = (mtime % 1000) * 1000; - (tempI64 = [Math.floor(ctime / 1000)>>>0,(tempDouble = Math.floor(ctime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(72))>>2)] = tempI64[0],HEAP32[(((buf)+(76))>>2)] = tempI64[1]); - HEAPU32[(((buf)+(80))>>2)] = (ctime % 1000) * 1000; - (tempI64 = [stat.ino>>>0,(tempDouble = stat.ino,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(88))>>2)] = tempI64[0],HEAP32[(((buf)+(92))>>2)] = tempI64[1]); + 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; + (tempI64 = [stat.size>>>0,(tempDouble=stat.size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(40))>>2)] = tempI64[0],HEAP32[(((buf)+(44))>>2)] = tempI64[1]); + HEAP32[(((buf)+(48))>>2)] = 4096; + HEAP32[(((buf)+(52))>>2)] = stat.blocks; + HEAP32[(((buf)+(56))>>2)] = (stat.atime.getTime() / 1000)|0; + HEAP32[(((buf)+(60))>>2)] = 0; + HEAP32[(((buf)+(64))>>2)] = (stat.mtime.getTime() / 1000)|0; + HEAP32[(((buf)+(68))>>2)] = 0; + HEAP32[(((buf)+(72))>>2)] = (stat.ctime.getTime() / 1000)|0; + HEAP32[(((buf)+(76))>>2)] = 0; + (tempI64 = [stat.ino>>>0,(tempDouble=stat.ino,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(80))>>2)] = tempI64[0],HEAP32[(((buf)+(84))>>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; - } + },doMsync:function(addr, stream, len, flags, offset) { 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) { + },varargs:undefined,get:function() { + SYSCALLS.varargs += 4; + var ret = HEAP32[(((SYSCALLS.varargs)-(4))>>2)]; + return ret; + },getStr:function(ptr) { var ret = UTF8ToString(ptr); return ret; - }, - }; + },getStreamFromFD:function(fd) { + var stream = FS.getStream(fd); + if (!stream) throw new FS.ErrnoError(8); + return stream; + }}; function ___syscall_fcntl64(fd, cmd, varargs) { SYSCALLS.varargs = varargs; try { @@ -3339,15 +3896,12 @@ var tempI64; var stream = SYSCALLS.getStreamFromFD(fd); switch (cmd) { case 0: { - var arg = syscallGetVarargI(); + var arg = SYSCALLS.get(); if (arg < 0) { return -28; } - while (FS.streams[arg]) { - arg++; - } var newStream; - newStream = FS.dupStream(stream, arg); + newStream = FS.createStream(stream, arg); return newStream.fd; } case 1: @@ -3356,24 +3910,39 @@ var tempI64; case 3: return stream.flags; case 4: { - var arg = syscallGetVarargI(); + var arg = SYSCALLS.get(); stream.flags |= arg; return 0; } - case 12: { - var arg = syscallGetVarargP(); + case 5: + /* case 5: Currently in musl F_GETLK64 has same value as F_GETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ { + + var arg = SYSCALLS.get(); var offset = 0; // We're always unlocked. HEAP16[(((arg)+(offset))>>1)] = 2; return 0; } - case 13: - case 14: + case 6: + case 7: + /* case 6: Currently in musl F_SETLK64 has same value as F_SETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ + /* case 7: Currently in musl F_SETLKW64 has same value as F_SETLKW, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ + + return 0; // Pretend that the locking is successful. + case 16: + case 8: + return -28; // These are for sockets. We don't have them fully implemented yet. + case 9: + // musl trusts getown return values, due to a bug where they must be, as they overlap with errors. just return -1 here, so fcntl() returns that, and we set errno ourselves. + setErrNo(28); + return -1; + default: { + return -28; + } } - return -28; } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3384,65 +3953,34 @@ var tempI64; var stream = SYSCALLS.getStreamFromFD(fd); return SYSCALLS.doStat(FS.stat, stream.path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.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 21509: 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 21512: 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(); + var argp = SYSCALLS.get(); HEAP32[((argp)>>2)] = 0; return 0; } @@ -3451,19 +3989,13 @@ var tempI64; return -28; // not supported } case 21531: { - var argp = syscallGetVarargP(); + var argp = SYSCALLS.get(); 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: { @@ -3473,14 +4005,10 @@ var tempI64; if (!stream.tty) return -59; return 0; } - case 21515: { - if (!stream.tty) return -59; - return 0; - } - default: return -28; // not supported + default: abort('bad ioctl syscall ' + op); } } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3491,7 +4019,7 @@ var tempI64; path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.lstat, path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3502,26 +4030,25 @@ var tempI64; path = SYSCALLS.getStr(path); var nofollow = flags & 256; var allowEmpty = flags & 4096; - flags = flags & (~6400); + flags = flags & (~4352); 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; + if (typeof FS == 'undefined' || !(e instanceof FS.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; + var mode = varargs ? SYSCALLS.get() : 0; return FS.open(path, flags, mode).fd; } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } @@ -3532,43 +4059,84 @@ var tempI64; path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.stat, path, buf); } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } } - var __abort_js = () => { - abort(''); - }; - - var structRegistrations = { - }; + var structRegistrations = {}; - var runDestructors = (destructors) => { + function runDestructors(destructors) { while (destructors.length) { var ptr = destructors.pop(); var del = destructors.pop(); del(ptr); } - }; + } - /** @suppress {globalThis} */ - function readPointer(pointer) { - return this['fromWireType'](HEAPU32[((pointer)>>2)]); + function simpleReadValueFromPointer(pointer) { + return this['fromWireType'](HEAPU32[pointer >> 2]); } - var awaitingDependencies = { - }; + var awaitingDependencies = {}; - var registeredTypes = { - }; + var registeredTypes = {}; - var typeDependencies = { - }; + var typeDependencies = {}; + + var char_0 = 48; + + var char_9 = 57; + function makeLegalFunctionName(name) { + if (undefined === name) { + return '_unknown'; + } + name = name.replace(/[^a-zA-Z0-9_]/g, '$'); + var f = name.charCodeAt(0); + if (f >= char_0 && f <= char_9) { + return '_' + name; + } + return name; + } + function createNamedFunction(name, body) { + name = makeLegalFunctionName(name); + /*jshint evil:true*/ + return new Function( + "body", + "return function " + name + "() {\n" + + " \"use strict\";" + + " return body.apply(this, arguments);\n" + + "};\n" + )(body); + } + function extendError(baseErrorType, errorName) { + var errorClass = createNamedFunction(errorName, function(message) { + this.name = errorName; + this.message = message; + + var stack = (new Error(message)).stack; + if (stack !== undefined) { + this.stack = this.toString() + '\n' + + stack.replace(/^Error(:[^\n]*)?\n/, ''); + } + }); + errorClass.prototype = Object.create(baseErrorType.prototype); + errorClass.prototype.constructor = errorClass; + errorClass.prototype.toString = function() { + if (this.message === undefined) { + return this.name; + } else { + return this.name + ': ' + this.message; + } + }; - var InternalError; - var throwInternalError = (message) => { throw new InternalError(message); }; - var whenDependentTypesAreResolved = (myTypes, dependentTypes, getTypeConverters) => { + return errorClass; + } + var InternalError = undefined; + function throwInternalError(message) { + throw new InternalError(message); + } + function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) { myTypes.forEach(function(type) { typeDependencies[type] = dependentTypes; }); @@ -3606,8 +4174,8 @@ var tempI64; if (0 === unregisteredTypes.length) { onComplete(typeConverters); } - }; - var __embind_finalize_value_object = (structType) => { + } + function __embind_finalize_value_object(structType) { var reg = structRegistrations[structType]; delete structRegistrations[structType]; @@ -3627,7 +4195,10 @@ var tempI64; var setter = field.setter; var setterContext = field.setterContext; fields[fieldName] = { - read: (ptr) => getterReturnType['fromWireType'](getter(getterContext, ptr)), + read: (ptr) => { + return getterReturnType['fromWireType']( + getter(getterContext, ptr)); + }, write: (ptr, o) => { var destructors = []; setter(setterContext, ptr, setterArgumentType['toWireType'](destructors, o)); @@ -3638,7 +4209,7 @@ var tempI64; return [{ name: reg.name, - 'fromWireType': (ptr) => { + 'fromWireType': function(ptr) { var rv = {}; for (var i in fields) { rv[i] = fields[i].read(ptr); @@ -3646,12 +4217,12 @@ var tempI64; rawDestructor(ptr); return rv; }, - 'toWireType': (destructors, o) => { + 'toWireType': function(destructors, o) { // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: // assume all fields are present without checking. for (var fieldName in fields) { if (!(fieldName in o)) { - throw new TypeError(`Missing field: "${fieldName}"`); + throw new TypeError('Missing field: "' + fieldName + '"'); } } var ptr = rawConstructor(); @@ -3663,50 +4234,63 @@ var tempI64; } return ptr; }, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': readPointer, + 'argPackAdvance': 8, + 'readValueFromPointer': simpleReadValueFromPointer, destructorFunction: rawDestructor, }]; }); - }; + } - var __embind_register_bigint = (primitiveType, name, size, minRange, maxRange) => {}; + function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) {} - var embind_init_charCodes = () => { + function getShiftFromSize(size) { + switch (size) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 8: return 3; + default: + throw new TypeError('Unknown type size: ' + size); + } + } + + function embind_init_charCodes() { var codes = new Array(256); for (var i = 0; i < 256; ++i) { codes[i] = String.fromCharCode(i); } embind_charCodes = codes; - }; - var embind_charCodes; - var readLatin1String = (ptr) => { + } + var embind_charCodes = undefined; + function readLatin1String(ptr) { var ret = ""; var c = ptr; while (HEAPU8[c]) { ret += embind_charCodes[HEAPU8[c++]]; } return ret; - }; - - - - - var BindingError; - var throwBindingError = (message) => { throw new BindingError(message); }; + } + var BindingError = undefined; + function throwBindingError(message) { + throw new BindingError(message); + } /** @param {Object=} options */ - function sharedRegisterType(rawType, registeredInstance, options = {}) { + function registerType(rawType, registeredInstance, options = {}) { + if (!('argPackAdvance' in registeredInstance)) { + throw new TypeError('registerType registeredInstance requires argPackAdvance'); + } + var name = registeredInstance.name; if (!rawType) { - throwBindingError(`type "${name}" must have a positive integer typeid pointer`); + throwBindingError('type "' + name + '" must have a positive integer typeid pointer'); } if (registeredTypes.hasOwnProperty(rawType)) { - if (options.ignoreDuplicateRegistrations) { - return; - } else { - throwBindingError(`Cannot register type '${name}' twice`); - } + if (options.ignoreDuplicateRegistrations) { + return; + } else { + throwBindingError("Cannot register type '" + name + "' twice"); + } } registeredTypes[rawType] = registeredInstance; @@ -3718,20 +4302,12 @@ var tempI64; callbacks.forEach((cb) => cb()); } } - /** @param {Object=} options */ - function registerType(rawType, registeredInstance, options = {}) { - if (!('argPackAdvance' in registeredInstance)) { - throw new TypeError('registerType registeredInstance requires argPackAdvance'); - } - return sharedRegisterType(rawType, registeredInstance, options); - } + function __embind_register_bool(rawType, name, size, trueValue, falseValue) { + var shift = getShiftFromSize(size); - var GenericWireTypeSize = 8; - /** @suppress {globalThis} */ - var __embind_register_bool = (rawType, name, trueValue, falseValue) => { name = readLatin1String(name); registerType(rawType, { - name, + name: name, 'fromWireType': function(wt) { // ambiguous emscripten ABI: sometimes return values are // true or false, and sometimes integers (0 or 1) @@ -3740,55 +4316,90 @@ var tempI64; 'toWireType': function(destructors, o) { return o ? trueValue : falseValue; }, - 'argPackAdvance': GenericWireTypeSize, + 'argPackAdvance': 8, 'readValueFromPointer': function(pointer) { - return this['fromWireType'](HEAPU8[pointer]); + // TODO: if heap is fixed (like in asm.js) this could be executed outside + var heap; + if (size === 1) { + heap = HEAP8; + } else if (size === 2) { + heap = HEAP16; + } else if (size === 4) { + heap = HEAP32; + } else { + throw new TypeError("Unknown boolean type size: " + name); + } + return this['fromWireType'](heap[pointer >> shift]); }, destructorFunction: null, // This type does not need a destructor }); - }; + } + function ClassHandle_isAliasOf(other) { + if (!(this instanceof ClassHandle)) { + return false; + } + if (!(other instanceof ClassHandle)) { + return false; + } + var leftClass = this.$$.ptrType.registeredClass; + var left = this.$$.ptr; + var rightClass = other.$$.ptrType.registeredClass; + var right = other.$$.ptr; - var shallowCopyInternalPointer = (o) => { + while (leftClass.baseClass) { + left = leftClass.upcast(left); + leftClass = leftClass.baseClass; + } + + while (rightClass.baseClass) { + right = rightClass.upcast(right); + rightClass = rightClass.baseClass; + } + + return leftClass === rightClass && left === right; + } + + function shallowCopyInternalPointer(o) { return { - count: o.count, - deleteScheduled: o.deleteScheduled, - preservePointerOnDelete: o.preservePointerOnDelete, - ptr: o.ptr, - ptrType: o.ptrType, - smartPtr: o.smartPtr, - smartPtrType: o.smartPtrType, + count: o.count, + deleteScheduled: o.deleteScheduled, + preservePointerOnDelete: o.preservePointerOnDelete, + ptr: o.ptr, + ptrType: o.ptrType, + smartPtr: o.smartPtr, + smartPtrType: o.smartPtrType, }; - }; + } - var throwInstanceAlreadyDeleted = (obj) => { + function throwInstanceAlreadyDeleted(obj) { function getInstanceTypeName(handle) { return handle.$$.ptrType.registeredClass.name; } throwBindingError(getInstanceTypeName(obj) + ' instance already deleted'); - }; + } var finalizationRegistry = false; - var detachFinalizer = (handle) => {}; + function detachFinalizer(handle) {} - var runDestructor = ($$) => { + function runDestructor($$) { if ($$.smartPtr) { - $$.smartPtrType.rawDestructor($$.smartPtr); + $$.smartPtrType.rawDestructor($$.smartPtr); } else { - $$.ptrType.registeredClass.rawDestructor($$.ptr); + $$.ptrType.registeredClass.rawDestructor($$.ptr); } - }; - var releaseClassHandle = ($$) => { + } + function releaseClassHandle($$) { $$.count.value -= 1; var toDelete = 0 === $$.count.value; if (toDelete) { runDestructor($$); } - }; + } - var downcastPointer = (ptr, ptrClass, desiredClass) => { + function downcastPointer(ptr, ptrClass, desiredClass) { if (ptrClass === desiredClass) { return ptr; } @@ -3798,54 +4409,52 @@ var tempI64; var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); if (rv === null) { - return null; + return null; } return desiredClass.downcast(rv); - }; + } - var registeredPointers = { - }; + var registeredPointers = {}; - var getInheritedInstanceCount = () => Object.keys(registeredInstances).length; + function getInheritedInstanceCount() { + return Object.keys(registeredInstances).length; + } - var getLiveInheritedInstances = () => { + function getLiveInheritedInstances() { var rv = []; for (var k in registeredInstances) { - if (registeredInstances.hasOwnProperty(k)) { - rv.push(registeredInstances[k]); - } + if (registeredInstances.hasOwnProperty(k)) { + rv.push(registeredInstances[k]); + } } return rv; - }; + } var deletionQueue = []; - var flushPendingDeletes = () => { + function flushPendingDeletes() { while (deletionQueue.length) { var obj = deletionQueue.pop(); obj.$$.deleteScheduled = false; obj['delete'](); } - }; - - var delayFunction; - + } - var setDelayFunction = (fn) => { + var delayFunction = undefined; + function setDelayFunction(fn) { delayFunction = fn; if (deletionQueue.length && delayFunction) { delayFunction(flushPendingDeletes); } - }; - var init_embind = () => { + } + function init_embind() { Module['getInheritedInstanceCount'] = getInheritedInstanceCount; Module['getLiveInheritedInstances'] = getLiveInheritedInstances; Module['flushPendingDeletes'] = flushPendingDeletes; Module['setDelayFunction'] = setDelayFunction; - }; - var registeredInstances = { - }; + } + var registeredInstances = {}; - var getBasestPointer = (class_, ptr) => { + function getBasestPointer(class_, ptr) { if (ptr === undefined) { throwBindingError('ptr should not be undefined'); } @@ -3854,14 +4463,13 @@ var tempI64; class_ = class_.baseClass; } return ptr; - }; - var getInheritedInstance = (class_, ptr) => { + } + function getInheritedInstance(class_, ptr) { ptr = getBasestPointer(class_, ptr); return registeredInstances[ptr]; - }; - + } - var makeClassHandle = (prototype, record) => { + function makeClassHandle(prototype, record) { if (!record.ptrType || !record.ptr) { throwInternalError('makeClassHandle requires ptr and ptrType'); } @@ -3873,12 +4481,10 @@ var tempI64; record.count = { value: 1 }; return attachFinalizer(Object.create(prototype, { $$: { - value: record, - writable: true, + value: record, }, })); - }; - /** @suppress {globalThis} */ + } function RegisteredPointer_fromWireType(ptr) { // ptr is a raw pointer (or a raw smartpointer) @@ -3916,7 +4522,7 @@ var tempI64; } else { return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this, - ptr, + ptr: ptr, }); } } @@ -3938,7 +4544,7 @@ var tempI64; this.registeredClass, toType.registeredClass); if (dp === null) { - return makeDefaultHandle.call(this); + return makeDefaultHandle.call(this); } if (this.isSmartPointer) { return makeClassHandle(toType.registeredClass.instancePrototype, { @@ -3954,17 +4560,17 @@ var tempI64; }); } } - var attachFinalizer = (handle) => { + function attachFinalizer(handle) { if ('undefined' === typeof FinalizationRegistry) { - attachFinalizer = (handle) => handle; - return handle; + attachFinalizer = (handle) => handle; + return handle; } // If the running environment has a FinalizationRegistry (see // https://github.com/tc39/proposal-weakrefs), then attach finalizers // for class handles. We check for the presence of FinalizationRegistry // at run-time, not build-time. finalizationRegistry = new FinalizationRegistry((info) => { - releaseClassHandle(info.$$); + releaseClassHandle(info.$$); }); attachFinalizer = (handle) => { var $$ = handle.$$; @@ -3978,136 +4584,102 @@ var tempI64; }; detachFinalizer = (handle) => finalizationRegistry.unregister(handle); return attachFinalizer(handle); - }; - - - - var init_ClassHandle = () => { - Object.assign(ClassHandle.prototype, { - "isAliasOf"(other) { - if (!(this instanceof ClassHandle)) { - return false; - } - if (!(other instanceof ClassHandle)) { - return false; - } - - var leftClass = this.$$.ptrType.registeredClass; - var left = this.$$.ptr; - other.$$ = /** @type {Object} */ (other.$$); - var rightClass = other.$$.ptrType.registeredClass; - var right = other.$$.ptr; - - while (leftClass.baseClass) { - left = leftClass.upcast(left); - leftClass = leftClass.baseClass; - } - - while (rightClass.baseClass) { - right = rightClass.upcast(right); - rightClass = rightClass.baseClass; - } - - return leftClass === rightClass && left === right; - }, - - "clone"() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - - if (this.$$.preservePointerOnDelete) { - this.$$.count.value += 1; - return this; - } else { - var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { - $$: { - value: shallowCopyInternalPointer(this.$$), - } - })); - - clone.$$.count.value += 1; - clone.$$.deleteScheduled = false; - return clone; - } - }, + } + function ClassHandle_clone() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } - "delete"() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); + if (this.$$.preservePointerOnDelete) { + this.$$.count.value += 1; + return this; + } else { + var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { + $$: { + value: shallowCopyInternalPointer(this.$$), } + })); - if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { - throwBindingError('Object already scheduled for deletion'); - } + clone.$$.count.value += 1; + clone.$$.deleteScheduled = false; + return clone; + } + } - detachFinalizer(this); - releaseClassHandle(this.$$); + function ClassHandle_delete() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } - if (!this.$$.preservePointerOnDelete) { - this.$$.smartPtr = undefined; - this.$$.ptr = undefined; - } - }, + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { + throwBindingError('Object already scheduled for deletion'); + } - "isDeleted"() { - return !this.$$.ptr; - }, + detachFinalizer(this); + releaseClassHandle(this.$$); - "deleteLater"() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { - throwBindingError('Object already scheduled for deletion'); - } - deletionQueue.push(this); - if (deletionQueue.length === 1 && delayFunction) { - delayFunction(flushPendingDeletes); - } - this.$$.deleteScheduled = true; - return this; - }, - }); - }; - /** @constructor */ - function ClassHandle() { + if (!this.$$.preservePointerOnDelete) { + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; + } } - var createNamedFunction = (name, body) => Object.defineProperty(body, 'name', { - value: name - }); + function ClassHandle_isDeleted() { + return !this.$$.ptr; + } + function ClassHandle_deleteLater() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { + throwBindingError('Object already scheduled for deletion'); + } + deletionQueue.push(this); + if (deletionQueue.length === 1 && delayFunction) { + delayFunction(flushPendingDeletes); + } + this.$$.deleteScheduled = true; + return this; + } + function init_ClassHandle() { + ClassHandle.prototype['isAliasOf'] = ClassHandle_isAliasOf; + ClassHandle.prototype['clone'] = ClassHandle_clone; + ClassHandle.prototype['delete'] = ClassHandle_delete; + ClassHandle.prototype['isDeleted'] = ClassHandle_isDeleted; + ClassHandle.prototype['deleteLater'] = ClassHandle_deleteLater; + } + function ClassHandle() { + } - var ensureOverloadTable = (proto, methodName, humanName) => { + function ensureOverloadTable(proto, methodName, humanName) { if (undefined === proto[methodName].overloadTable) { var prevFunc = proto[methodName]; // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. - proto[methodName] = function(...args) { + proto[methodName] = function() { // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!proto[methodName].overloadTable.hasOwnProperty(args.length)) { - throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`); + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); } - return proto[methodName].overloadTable[args.length].apply(this, args); + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); }; // Move the previous function into the overload table. proto[methodName].overloadTable = []; proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; } - }; - + } /** @param {number=} numArguments */ - var exposePublicSymbol = (name, value, numArguments) => { + function exposePublicSymbol(name, value, numArguments) { if (Module.hasOwnProperty(name)) { if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { - throwBindingError(`Cannot register public name '${name}' twice`); + throwBindingError("Cannot register public name '" + name + "' twice"); } // We are exposing a function with the same name as an existing function. Create an overload table and a function selector // that routes between the two. ensureOverloadTable(Module, name, name); if (Module.hasOwnProperty(numArguments)) { - throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`); + throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); } // Add the new function into the overload table. Module[name].overloadTable[numArguments] = value; @@ -4118,23 +4690,7 @@ var tempI64; Module[name].numArguments = numArguments; } } - }; - - var char_0 = 48; - - var char_9 = 57; - var makeLegalFunctionName = (name) => { - if (undefined === name) { - return '_unknown'; - } - name = name.replace(/[^a-zA-Z0-9_]/g, '$'); - var f = name.charCodeAt(0); - if (f >= char_0 && f <= char_9) { - return `_${name}`; - } - return name; - }; - + } /** @constructor */ function RegisteredClass(name, @@ -4156,44 +4712,40 @@ var tempI64; this.pureVirtualFunctions = []; } - - var upcastPointer = (ptr, ptrClass, desiredClass) => { + function upcastPointer(ptr, ptrClass, desiredClass) { while (ptrClass !== desiredClass) { if (!ptrClass.upcast) { - throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`); + throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); } ptr = ptrClass.upcast(ptr); ptrClass = ptrClass.baseClass; } return ptr; - }; - /** @suppress {globalThis} */ + } function constNoSmartPtrRawPointerToWireType(destructors, handle) { if (handle === null) { if (this.isReference) { - throwBindingError(`null is not a valid ${this.name}`); + throwBindingError('null is not a valid ' + this.name); } return 0; } if (!handle.$$) { - throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); } if (!handle.$$.ptr) { - throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); + throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; } - - /** @suppress {globalThis} */ function genericPointerToWireType(destructors, handle) { var ptr; if (handle === null) { if (this.isReference) { - throwBindingError(`null is not a valid ${this.name}`); + throwBindingError('null is not a valid ' + this.name); } if (this.isSmartPointer) { @@ -4207,14 +4759,14 @@ var tempI64; } } - if (!handle || !handle.$$) { - throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); } if (!handle.$$.ptr) { - throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); + throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } if (!this.isConst && handle.$$.ptrType.isConst) { - throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); + throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); } var handleClass = handle.$$.ptrType.registeredClass; ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); @@ -4233,7 +4785,7 @@ var tempI64; if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; } else { - throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); + throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); } break; @@ -4248,7 +4800,9 @@ var tempI64; var clonedHandle = handle['clone'](); ptr = this.rawShare( ptr, - Emval.toHandle(() => clonedHandle['delete']()) + Emval.toHandle(function() { + clonedHandle['delete'](); + }) ); if (destructors !== null) { destructors.push(this.rawDestructor, ptr); @@ -4263,49 +4817,54 @@ var tempI64; return ptr; } - - /** @suppress {globalThis} */ function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) { if (handle === null) { if (this.isReference) { - throwBindingError(`null is not a valid ${this.name}`); + throwBindingError('null is not a valid ' + this.name); } return 0; } if (!handle.$$) { - throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); } if (!handle.$$.ptr) { - throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); + throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } if (handle.$$.ptrType.isConst) { - throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`); + throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; } + function RegisteredPointer_getPointee(ptr) { + if (this.rawGetPointee) { + ptr = this.rawGetPointee(ptr); + } + return ptr; + } + function RegisteredPointer_destructor(ptr) { + if (this.rawDestructor) { + this.rawDestructor(ptr); + } + } - - var init_RegisteredPointer = () => { - Object.assign(RegisteredPointer.prototype, { - getPointee(ptr) { - if (this.rawGetPointee) { - ptr = this.rawGetPointee(ptr); - } - return ptr; - }, - destructor(ptr) { - this.rawDestructor?.(ptr); - }, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': readPointer, - 'fromWireType': RegisteredPointer_fromWireType, - }); - }; + function RegisteredPointer_deleteObject(handle) { + if (handle !== null) { + handle['delete'](); + } + } + function init_RegisteredPointer() { + RegisteredPointer.prototype.getPointee = RegisteredPointer_getPointee; + RegisteredPointer.prototype.destructor = RegisteredPointer_destructor; + RegisteredPointer.prototype['argPackAdvance'] = 8; + RegisteredPointer.prototype['readValueFromPointer'] = simpleReadValueFromPointer; + RegisteredPointer.prototype['deleteObject'] = RegisteredPointer_deleteObject; + RegisteredPointer.prototype['fromWireType'] = RegisteredPointer_fromWireType; + } /** @constructor @param {*=} pointeeType, @param {*=} sharingPolicy, @@ -4361,9 +4920,9 @@ var tempI64; } /** @param {number=} numArguments */ - var replacePublicSymbol = (name, value, numArguments) => { + function replacePublicSymbol(name, value, numArguments) { if (!Module.hasOwnProperty(name)) { - throwInternalError('Replacing nonexistent public symbol'); + throwInternalError('Replacing nonexistant public symbol'); } // If there's an overload table for this symbol, replace the symbol in the overload table instead. if (undefined !== Module[name].overloadTable && undefined !== numArguments) { @@ -4373,45 +4932,31 @@ var tempI64; Module[name] = value; Module[name].argCount = numArguments; } - }; - - - - var dynCallLegacy = (sig, ptr, args) => { - sig = sig.replace(/p/g, 'i') - var f = Module['dynCall_' + sig]; - return f(ptr, ...args); - }; - - var wasmTableMirror = []; - - /** @type {WebAssembly.Table} */ - var wasmTable; - var getWasmTableEntry = (funcPtr) => { - var func = wasmTableMirror[funcPtr]; - if (!func) { - if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; - wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); - } - return func; - }; + } - var dynCall = (sig, ptr, args = []) => { + function dynCallLegacy(sig, ptr, args) { + var f = Module["dynCall_" + sig]; + return args && args.length ? f.apply(null, [ptr].concat(args)) : f.call(null, ptr); + } + /** @param {Object=} args */ + function dynCall(sig, ptr, args) { // Without WASM_BIGINT support we cannot directly call function with i64 as - // part of their signature, so we rely on the dynCall functions generated by + // part of thier signature, so we rely the dynCall functions generated by // wasm-emscripten-finalize if (sig.includes('j')) { return dynCallLegacy(sig, ptr, args); } - var rtn = getWasmTableEntry(ptr)(...args); - return rtn; - }; - var getDynCaller = (sig, ptr) => { - return (...args) => dynCall(sig, ptr, args); - }; - - - var embind__requireFunction = (signature, rawFunction) => { + return getWasmTableEntry(ptr).apply(null, args) + } + function getDynCaller(sig, ptr) { + var argCache = []; + return function() { + argCache.length = 0; + Object.assign(argCache, arguments); + return dynCall(sig, ptr, argCache); + }; + } + function embind__requireFunction(signature, rawFunction) { signature = readLatin1String(signature); function makeDynCaller() { @@ -4423,47 +4968,20 @@ var tempI64; var fp = makeDynCaller(); if (typeof fp != "function") { - throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`); + throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); } return fp; - }; - - - - var extendError = (baseErrorType, errorName) => { - var errorClass = createNamedFunction(errorName, function(message) { - this.name = errorName; - this.message = message; - - var stack = (new Error(message)).stack; - if (stack !== undefined) { - this.stack = this.toString() + '\n' + - stack.replace(/^Error(:[^\n]*)?\n/, ''); - } - }); - errorClass.prototype = Object.create(baseErrorType.prototype); - errorClass.prototype.constructor = errorClass; - errorClass.prototype.toString = function() { - if (this.message === undefined) { - return this.name; - } else { - return `${this.name}: ${this.message}`; - } - }; - - return errorClass; - }; - var UnboundTypeError; - + } + var UnboundTypeError = undefined; - var getTypeName = (type) => { + function getTypeName(type) { var ptr = ___getTypeName(type); var rv = readLatin1String(ptr); _free(ptr); return rv; - }; - var throwUnboundTypeError = (message, types) => { + } + function throwUnboundTypeError(message, types) { var unboundTypes = []; var seen = {}; function visit(type) { @@ -4482,38 +5000,41 @@ var tempI64; } types.forEach(visit); - throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([', '])); - }; - - var __embind_register_class = (rawType, - rawPointerType, - rawConstPointerType, - baseClassRawType, - getActualTypeSignature, - getActualType, - upcastSignature, - upcast, - downcastSignature, - downcast, - name, - destructorSignature, - rawDestructor) => { + throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', '])); + } + function __embind_register_class(rawType, + rawPointerType, + rawConstPointerType, + baseClassRawType, + getActualTypeSignature, + getActualType, + upcastSignature, + upcast, + downcastSignature, + downcast, + name, + destructorSignature, + rawDestructor) { name = readLatin1String(name); getActualType = embind__requireFunction(getActualTypeSignature, getActualType); - upcast &&= embind__requireFunction(upcastSignature, upcast); - downcast &&= embind__requireFunction(downcastSignature, downcast); + if (upcast) { + upcast = embind__requireFunction(upcastSignature, upcast); + } + if (downcast) { + downcast = embind__requireFunction(downcastSignature, downcast); + } rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); var legalFunctionName = makeLegalFunctionName(name); exposePublicSymbol(legalFunctionName, function() { // this code cannot run if baseClassRawType is zero - throwUnboundTypeError(`Cannot construct ${name} due to unbound types`, [baseClassRawType]); + throwUnboundTypeError('Cannot construct ' + name + ' due to unbound types', [baseClassRawType]); }); whenDependentTypesAreResolved( [rawType, rawPointerType, rawConstPointerType], baseClassRawType ? [baseClassRawType] : [], - (base) => { + function(base) { base = base[0]; var baseClass; @@ -4525,18 +5046,18 @@ var tempI64; basePrototype = ClassHandle.prototype; } - var constructor = createNamedFunction(name, function(...args) { + var constructor = createNamedFunction(legalFunctionName, function() { if (Object.getPrototypeOf(this) !== instancePrototype) { throw new BindingError("Use 'new' to construct " + name); } if (undefined === registeredClass.constructor_body) { throw new BindingError(name + " has no accessible constructor"); } - var body = registeredClass.constructor_body[args.length]; + var body = registeredClass.constructor_body[arguments.length]; if (undefined === body) { - throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`); + throw new BindingError("Tried to invoke ctor of " + name + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); } - return body.apply(this, args); + return body.apply(this, arguments); }); var instancePrototype = Object.create(basePrototype, { @@ -4554,13 +5075,6 @@ var tempI64; upcast, downcast); - if (registeredClass.baseClass) { - // Keep track of class hierarchy. Used to allow sub-classes to inherit class functions. - registeredClass.baseClass.__derivedClasses ??= []; - - registeredClass.baseClass.__derivedClasses.push(registeredClass); - } - var referenceConverter = new RegisteredPointer(name, registeredClass, true, @@ -4589,40 +5103,56 @@ var tempI64; return [referenceConverter, pointerConverter, constPointerConverter]; } ); - }; + } - var heap32VectorToArray = (count, firstElement) => { + function heap32VectorToArray(count, firstElement) { var array = []; for (var i = 0; i < count; i++) { - // TODO(https://github.com/emscripten-core/emscripten/issues/17310): - // Find a way to hoist the `>> 2` or `>> 3` out of this loop. - array.push(HEAPU32[(((firstElement)+(i * 4))>>2)]); + array.push(HEAP32[(firstElement >> 2) + i]); } return array; - }; - - - - - - - + } + function __embind_register_class_constructor( + rawClassType, + argCount, + rawArgTypesAddr, + invokerSignature, + invoker, + rawConstructor + ) { + assert(argCount > 0); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + invoker = embind__requireFunction(invokerSignature, invoker); + var args = [rawConstructor]; + var destructors = []; + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; + var humanName = 'constructor ' + classType.name; - function usesDestructorStack(argTypes) { - // Skip return value at index 0 - it's not deleted here. - for (var i = 1; i < argTypes.length; ++i) { - // The type does not define a destructor function - must use dynamic stack - if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { - return true; + if (undefined === classType.registeredClass.constructor_body) { + classType.registeredClass.constructor_body = []; } - } - return false; - } + if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { + throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount-1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); + } + classType.registeredClass.constructor_body[argCount - 1] = () => { + throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes); + }; - function newFunc(constructor, argumentList) { + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + // Insert empty slot for context type (argTypes[1]). + argTypes.splice(1, 0, null); + classType.registeredClass.constructor_body[argCount - 1] = craftInvokerFunction(humanName, argTypes, null, invoker, rawConstructor); + return []; + }); + return []; + }); + } + + function new_(constructor, argumentList) { if (!(constructor instanceof Function)) { - throw new TypeError(`new_ called with constructor type ${typeof(constructor)} which is not a function`); + throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function"); } /* * Previously, the following line was just: @@ -4631,7 +5161,7 @@ var tempI64; * though at creation, the 'dummy' has the correct constructor name. Thus, * objects created with IMVU.new would show up in the debugger as 'dummy', * which isn't very helpful. Using IMVU.createNamedFunction addresses the - * issue. Doubly-unfortunately, there's no way to write a test for this + * issue. Doublely-unfortunately, there's no way to write a test for this * behavior. -NRD 2013.02.22 */ var dummy = createNamedFunction(constructor.name || 'unknownFunctionName', function(){}); @@ -4641,71 +5171,7 @@ var tempI64; var r = constructor.apply(obj, argumentList); return (r instanceof Object) ? r : obj; } - - function createJsInvoker(argTypes, isClassMethodFunc, returns, isAsync) { - var needsDestructorStack = usesDestructorStack(argTypes); - var argCount = argTypes.length; - var argsList = ""; - var argsListWired = ""; - for (var i = 0; i < argCount - 2; ++i) { - argsList += (i!==0?", ":"")+"arg"+i; - argsListWired += (i!==0?", ":"")+"arg"+i+"Wired"; - } - - var invokerFnBody = ` - return function (${argsList}) { - if (arguments.length !== ${argCount - 2}) { - throwBindingError('function ' + humanName + ' called with ' + arguments.length + ' arguments, expected ${argCount - 2}'); - }`; - - if (needsDestructorStack) { - invokerFnBody += "var destructors = [];\n"; - } - - var dtorStack = needsDestructorStack ? "destructors" : "null"; - var args1 = ["humanName", "throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; - - if (isClassMethodFunc) { - invokerFnBody += "var thisWired = classParam['toWireType']("+dtorStack+", this);\n"; - } - - for (var i = 0; i < argCount - 2; ++i) { - invokerFnBody += "var arg"+i+"Wired = argType"+i+"['toWireType']("+dtorStack+", arg"+i+");\n"; - args1.push("argType"+i); - } - - if (isClassMethodFunc) { - argsListWired = "thisWired" + (argsListWired.length > 0 ? ", " : "") + argsListWired; - } - - invokerFnBody += - (returns || isAsync ? "var rv = ":"") + "invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n"; - - var returnVal = returns ? "rv" : ""; - - if (needsDestructorStack) { - invokerFnBody += "runDestructors(destructors);\n"; - } else { - for (var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. - var paramName = (i === 1 ? "thisWired" : ("arg"+(i - 2)+"Wired")); - if (argTypes[i].destructorFunction !== null) { - invokerFnBody += `${paramName}_dtor(${paramName});\n`; - args1.push(`${paramName}_dtor`); - } - } - } - - if (returns) { - invokerFnBody += "var ret = retType['fromWireType'](rv);\n" + - "return ret;\n"; - } else { - } - - invokerFnBody += "}\n"; - - return [args1, invokerFnBody]; - } - function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) { + function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { // humanName: a human-readable string name for the function to be generated. // argTypes: An array that contains the embind type objects for all types in the function signature. // argTypes[0] is the type object for the function return value. @@ -4714,7 +5180,6 @@ var tempI64; // classType: The embind type object for the class to be bound, or null if this is not a method of a class. // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. - // isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI. var argCount = argTypes.length; if (argCount < 2) { @@ -4731,98 +5196,96 @@ var tempI64; // Determine if we need to use a dynamic stack to store the destructors for the function parameters. // TODO: Remove this completely once all function invokers are being dynamically generated. - var needsDestructorStack = usesDestructorStack(argTypes); + var needsDestructorStack = false; + + for (var i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. + if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack + needsDestructorStack = true; + break; + } + } var returns = (argTypes[0].name !== "void"); - // Builld the arguments that will be passed into the closure around the invoker - // function. - var closureArgs = [humanName, throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; - for (var i = 0; i < argCount - 2; ++i) { - closureArgs.push(argTypes[i+2]); - } - if (!needsDestructorStack) { - for (var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. - if (argTypes[i].destructorFunction !== null) { - closureArgs.push(argTypes[i].destructorFunction); - } + var argsList = ""; + var argsListWired = ""; + for (var i = 0; i < argCount - 2; ++i) { + argsList += (i!==0?", ":"")+"arg"+i; + argsListWired += (i!==0?", ":"")+"arg"+i+"Wired"; } - } - let [args, invokerFnBody] = createJsInvoker(argTypes, isClassMethodFunc, returns, isAsync); - args.push(invokerFnBody); - var invokerFn = newFunc(Function, args)(...closureArgs); - return createNamedFunction(humanName, invokerFn); - } - var __embind_register_class_constructor = ( - rawClassType, - argCount, - rawArgTypesAddr, - invokerSignature, - invoker, - rawConstructor - ) => { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - invoker = embind__requireFunction(invokerSignature, invoker); - var args = [rawConstructor]; - var destructors = []; + var invokerFnBody = + "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + + "if (arguments.length !== "+(argCount - 2)+") {\n" + + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + + "}\n"; - whenDependentTypesAreResolved([], [rawClassType], (classType) => { - classType = classType[0]; - var humanName = `constructor ${classType.name}`; + if (needsDestructorStack) { + invokerFnBody += "var destructors = [];\n"; + } - if (undefined === classType.registeredClass.constructor_body) { - classType.registeredClass.constructor_body = []; - } - if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { - throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`); - } - classType.registeredClass.constructor_body[argCount - 1] = () => { - throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`, rawArgTypes); - }; + var dtorStack = needsDestructorStack ? "destructors" : "null"; + var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; - whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { - // Insert empty slot for context type (argTypes[1]). - argTypes.splice(1, 0, null); - classType.registeredClass.constructor_body[argCount - 1] = craftInvokerFunction(humanName, argTypes, null, invoker, rawConstructor); - return []; - }); - return []; - }); - }; - + if (isClassMethodFunc) { + invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; + } + + for (var i = 0; i < argCount - 2; ++i) { + invokerFnBody += "var arg"+i+"Wired = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; + args1.push("argType"+i); + args2.push(argTypes[i+2]); + } + + if (isClassMethodFunc) { + argsListWired = "thisWired" + (argsListWired.length > 0 ? ", " : "") + argsListWired; + } + invokerFnBody += + (returns?"var rv = ":"") + "invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n"; + if (needsDestructorStack) { + invokerFnBody += "runDestructors(destructors);\n"; + } else { + for (var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. + var paramName = (i === 1 ? "thisWired" : ("arg"+(i - 2)+"Wired")); + if (argTypes[i].destructorFunction !== null) { + invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n"; + args1.push(paramName+"_dtor"); + args2.push(argTypes[i].destructorFunction); + } + } + } + if (returns) { + invokerFnBody += "var ret = retType.fromWireType(rv);\n" + + "return ret;\n"; + } else { + } + invokerFnBody += "}\n"; + args1.push(invokerFnBody); - var getFunctionName = (signature) => { - signature = signature.trim(); - const argsIndex = signature.indexOf("("); - if (argsIndex !== -1) { - return signature.substr(0, argsIndex); - } else { - return signature; - } - }; - var __embind_register_class_function = (rawClassType, - methodName, - argCount, - rawArgTypesAddr, // [ReturnType, ThisType, Args...] - invokerSignature, - rawInvoker, - context, - isPureVirtual, - isAsync) => { + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; + } + function __embind_register_class_function(rawClassType, + methodName, + argCount, + rawArgTypesAddr, // [ReturnType, ThisType, Args...] + invokerSignature, + rawInvoker, + context, + isPureVirtual) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); - methodName = getFunctionName(methodName); rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); - whenDependentTypesAreResolved([], [rawClassType], (classType) => { + whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; - var humanName = `${classType.name}.${methodName}`; + var humanName = classType.name + '.' + methodName; if (methodName.startsWith("@@")) { methodName = Symbol[methodName.substring(2)]; @@ -4833,7 +5296,7 @@ var tempI64; } function unboundTypesHandler() { - throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); + throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); } var proto = classType.registeredClass.instancePrototype; @@ -4851,13 +5314,11 @@ var tempI64; proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; } - whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { - var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context, isAsync); + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context); - // Replace the initial unbound-handler-stub function with the - // appropriate member function, now that all types are resolved. If - // multiple overloads are registered for this function, the function - // goes into an overload table. + // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types + // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. if (undefined === proto[methodName].overloadTable) { // Set argCount in case an overload is registered later memberFunction.argCount = argCount - 2; @@ -4870,140 +5331,140 @@ var tempI64; }); return []; }); - }; + } - - var __embind_register_constant = (name, type, value) => { + function __embind_register_constant(name, type, value) { name = readLatin1String(name); - whenDependentTypesAreResolved([], [type], (type) => { + whenDependentTypesAreResolved([], [type], function(type) { type = type[0]; Module[name] = type['fromWireType'](value); return []; }); - }; + } + var emval_free_list = []; - var emval_freelist = []; - - var emval_handles = []; - var __emval_decref = (handle) => { - if (handle > 9 && 0 === --emval_handles[handle + 1]) { - emval_handles[handle] = undefined; - emval_freelist.push(handle); + var emval_handle_array = [{},{value:undefined},{value:null},{value:true},{value:false}]; + function __emval_decref(handle) { + if (handle > 4 && 0 === --emval_handle_array[handle].refcount) { + emval_handle_array[handle] = undefined; + emval_free_list.push(handle); } - }; - - - - + } - var count_emval_handles = () => { - return emval_handles.length / 2 - 5 - emval_freelist.length; - }; + function count_emval_handles() { + var count = 0; + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== undefined) { + ++count; + } + } + return count; + } - var init_emval = () => { - // reserve 0 and some special values. These never get de-allocated. - emval_handles.push( - 0, 1, - undefined, 1, - null, 1, - true, 1, - false, 1, - ); + function get_first_emval() { + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== undefined) { + return emval_handle_array[i]; + } + } + return null; + } + function init_emval() { Module['count_emval_handles'] = count_emval_handles; - }; - var Emval = { - toValue:(handle) => { + Module['get_first_emval'] = get_first_emval; + } + var Emval = {toValue:(handle) => { if (!handle) { throwBindingError('Cannot use deleted val. handle = ' + handle); } - return emval_handles[handle]; - }, - toHandle:(value) => { + return emval_handle_array[handle].value; + },toHandle:(value) => { switch (value) { - case undefined: return 2; - case null: return 4; - case true: return 6; - case false: return 8; + case undefined: return 1; + case null: return 2; + case true: return 3; + case false: return 4; default:{ - const handle = emval_freelist.pop() || emval_handles.length; - emval_handles[handle] = value; - emval_handles[handle + 1] = 1; + var handle = emval_free_list.length ? + emval_free_list.pop() : + emval_handle_array.length; + + emval_handle_array[handle] = {refcount: 1, value: value}; return handle; } } - }, - }; - + }}; + function __embind_register_emval(rawType, name) { + name = readLatin1String(name); + registerType(rawType, { + name: name, + 'fromWireType': function(handle) { + var rv = Emval.toValue(handle); + __emval_decref(handle); + return rv; + }, + 'toWireType': function(destructors, value) { + return Emval.toHandle(value); + }, + 'argPackAdvance': 8, + 'readValueFromPointer': simpleReadValueFromPointer, + destructorFunction: null, // This type does not need a destructor - var EmValType = { - name: 'emscripten::val', - 'fromWireType': (handle) => { - var rv = Emval.toValue(handle); - __emval_decref(handle); - return rv; - }, - 'toWireType': (destructors, value) => Emval.toHandle(value), - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': readPointer, - destructorFunction: null, // This type does not need a destructor - - // TODO: do we need a deleteObject here? write a test where - // emval is passed into JS via an interface - }; - var __embind_register_emval = (rawType) => registerType(rawType, EmValType); + // TODO: do we need a deleteObject here? write a test where + // emval is passed into JS via an interface + }); + } - - var enumReadValueFromPointer = (name, width, signed) => { - switch (width) { - case 1: return signed ? - function(pointer) { return this['fromWireType'](HEAP8[pointer]) } : - function(pointer) { return this['fromWireType'](HEAPU8[pointer]) }; - case 2: return signed ? - function(pointer) { return this['fromWireType'](HEAP16[((pointer)>>1)]) } : - function(pointer) { return this['fromWireType'](HEAPU16[((pointer)>>1)]) }; - case 4: return signed ? - function(pointer) { return this['fromWireType'](HEAP32[((pointer)>>2)]) } : - function(pointer) { return this['fromWireType'](HEAPU32[((pointer)>>2)]) }; + function enumReadValueFromPointer(name, shift, signed) { + switch (shift) { + case 0: return function(pointer) { + var heap = signed ? HEAP8 : HEAPU8; + return this['fromWireType'](heap[pointer]); + }; + case 1: return function(pointer) { + var heap = signed ? HEAP16 : HEAPU16; + return this['fromWireType'](heap[pointer >> 1]); + }; + case 2: return function(pointer) { + var heap = signed ? HEAP32 : HEAPU32; + return this['fromWireType'](heap[pointer >> 2]); + }; default: - throw new TypeError(`invalid integer width (${width}): ${name}`); + throw new TypeError("Unknown integer type: " + name); } - }; - - - /** @suppress {globalThis} */ - var __embind_register_enum = (rawType, name, size, isSigned) => { + } + function __embind_register_enum(rawType, name, size, isSigned) { + var shift = getShiftFromSize(size); name = readLatin1String(name); function ctor() {} ctor.values = {}; registerType(rawType, { - name, + name: name, constructor: ctor, 'fromWireType': function(c) { return this.constructor.values[c]; }, - 'toWireType': (destructors, c) => c.value, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': enumReadValueFromPointer(name, size, isSigned), + 'toWireType': function(destructors, c) { + return c.value; + }, + 'argPackAdvance': 8, + 'readValueFromPointer': enumReadValueFromPointer(name, shift, isSigned), destructorFunction: null, }); exposePublicSymbol(name, ctor); - }; + } - - - - - var requireRegisteredType = (rawType, humanName) => { + function requireRegisteredType(rawType, humanName) { var impl = registeredTypes[rawType]; if (undefined === impl) { - throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`); + throwBindingError(humanName + " has unknown type " + getTypeName(rawType)); } return impl; - }; - var __embind_register_enum_value = (rawEnumType, name, enumValue) => { + } + function __embind_register_enum_value(rawEnumType, name, enumValue) { var enumType = requireRegisteredType(rawEnumType, 'enum'); name = readLatin1String(name); @@ -5011,13 +5472,13 @@ var tempI64; var Value = Object.create(enumType.constructor.prototype, { value: {value: enumValue}, - constructor: {value: createNamedFunction(`${enumType.name}_${name}`, function() {})}, + constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, }); Enum.values[enumValue] = Value; Enum[name] = Value; - }; + } - var embindRepr = (v) => { + function _embind_repr(v) { if (v === null) { return 'null'; } @@ -5027,97 +5488,85 @@ var tempI64; } else { return '' + v; } - }; + } - var floatReadValueFromPointer = (name, width) => { - switch (width) { - case 4: return function(pointer) { - return this['fromWireType'](HEAPF32[((pointer)>>2)]); + function floatReadValueFromPointer(name, shift) { + switch (shift) { + case 2: return function(pointer) { + return this['fromWireType'](HEAPF32[pointer >> 2]); }; - case 8: return function(pointer) { - return this['fromWireType'](HEAPF64[((pointer)>>3)]); + case 3: return function(pointer) { + return this['fromWireType'](HEAPF64[pointer >> 3]); }; default: - throw new TypeError(`invalid float width (${width}): ${name}`); + throw new TypeError("Unknown float type: " + name); } - }; - - - var __embind_register_float = (rawType, name, size) => { + } + function __embind_register_float(rawType, name, size) { + var shift = getShiftFromSize(size); name = readLatin1String(name); registerType(rawType, { - name, - 'fromWireType': (value) => value, - 'toWireType': (destructors, value) => { - // The VM will perform JS to Wasm value conversion, according to the spec: - // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue - return value; - }, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': floatReadValueFromPointer(name, size), - destructorFunction: null, // This type does not need a destructor + name: name, + 'fromWireType': function(value) { + return value; + }, + 'toWireType': function(destructors, value) { + // The VM will perform JS to Wasm value conversion, according to the spec: + // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue + return value; + }, + 'argPackAdvance': 8, + 'readValueFromPointer': floatReadValueFromPointer(name, shift), + destructorFunction: null, // This type does not need a destructor }); - }; + } - - - - - - - - - var __embind_register_function = (name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync) => { + function __embind_register_function(name, argCount, rawArgTypesAddr, signature, rawInvoker, fn) { var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = readLatin1String(name); - name = getFunctionName(name); rawInvoker = embind__requireFunction(signature, rawInvoker); exposePublicSymbol(name, function() { - throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); + throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); }, argCount - 1); - whenDependentTypesAreResolved([], argTypes, (argTypes) => { - var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); - replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn, isAsync), argCount - 1); - return []; + whenDependentTypesAreResolved([], argTypes, function(argTypes) { + var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); + replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn), argCount - 1); + return []; }); - }; + } - - var integerReadValueFromPointer = (name, width, signed) => { + function integerReadValueFromPointer(name, shift, signed) { // integers are quite common, so generate very specialized functions - switch (width) { + switch (shift) { + case 0: return signed ? + function readS8FromPointer(pointer) { return HEAP8[pointer]; } : + function readU8FromPointer(pointer) { return HEAPU8[pointer]; }; case 1: return signed ? - (pointer) => HEAP8[pointer] : - (pointer) => HEAPU8[pointer]; + function readS16FromPointer(pointer) { return HEAP16[pointer >> 1]; } : + function readU16FromPointer(pointer) { return HEAPU16[pointer >> 1]; }; case 2: return signed ? - (pointer) => HEAP16[((pointer)>>1)] : - (pointer) => HEAPU16[((pointer)>>1)] - case 4: return signed ? - (pointer) => HEAP32[((pointer)>>2)] : - (pointer) => HEAPU32[((pointer)>>2)] + function readS32FromPointer(pointer) { return HEAP32[pointer >> 2]; } : + function readU32FromPointer(pointer) { return HEAPU32[pointer >> 2]; }; default: - throw new TypeError(`invalid integer width (${width}): ${name}`); + throw new TypeError("Unknown integer type: " + name); } - }; - - - /** @suppress {globalThis} */ - var __embind_register_integer = (primitiveType, name, size, minRange, maxRange) => { + } + function __embind_register_integer(primitiveType, name, size, minRange, maxRange) { name = readLatin1String(name); - // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come - // out as 'i32 -1'. Always treat those as max u32. - if (maxRange === -1) { - maxRange = 4294967295; + if (maxRange === -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32. + maxRange = 4294967295; } + var shift = getShiftFromSize(size); + var fromWireType = (value) => value; if (minRange === 0) { - var bitshift = 32 - 8*size; - fromWireType = (value) => (value << bitshift) >>> bitshift; + var bitshift = 32 - 8*size; + fromWireType = (value) => (value << bitshift) >>> bitshift; } var isUnsignedType = (name.includes('unsigned')); @@ -5125,30 +5574,29 @@ var tempI64; } var toWireType; if (isUnsignedType) { - toWireType = function(destructors, value) { - checkAssertions(value, this.name); - return value >>> 0; - } + toWireType = function(destructors, value) { + checkAssertions(value, this.name); + return value >>> 0; + } } else { - toWireType = function(destructors, value) { - checkAssertions(value, this.name); - // The VM will perform JS to Wasm value conversion, according to the spec: - // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue - return value; - } + toWireType = function(destructors, value) { + checkAssertions(value, this.name); + // The VM will perform JS to Wasm value conversion, according to the spec: + // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue + return value; + } } registerType(primitiveType, { - name, - 'fromWireType': fromWireType, - 'toWireType': toWireType, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': integerReadValueFromPointer(name, size, minRange !== 0), - destructorFunction: null, // This type does not need a destructor + name: name, + 'fromWireType': fromWireType, + 'toWireType': toWireType, + 'argPackAdvance': 8, + 'readValueFromPointer': integerReadValueFromPointer(name, shift, minRange !== 0), + destructorFunction: null, // This type does not need a destructor }); - }; + } - - var __embind_register_memory_view = (rawType, dataTypeIndex, name) => { + function __embind_register_memory_view(rawType, dataTypeIndex, name) { var typeMapping = [ Int8Array, Uint8Array, @@ -5163,272 +5611,145 @@ var tempI64; var TA = typeMapping[dataTypeIndex]; function decodeMemoryView(handle) { - var size = HEAPU32[((handle)>>2)]; - var data = HEAPU32[(((handle)+(4))>>2)]; - return new TA(HEAP8.buffer, data, size); + handle = handle >> 2; + var heap = HEAPU32; + var size = heap[handle]; // in elements + var data = heap[handle + 1]; // byte offset into emscripten heap + return new TA(buffer, data, size); } name = readLatin1String(name); registerType(rawType, { - name, + name: name, 'fromWireType': decodeMemoryView, - 'argPackAdvance': GenericWireTypeSize, + 'argPackAdvance': 8, 'readValueFromPointer': decodeMemoryView, }, { ignoreDuplicateRegistrations: true, }); - }; + } - - - - - var stringToUTF8 = (str, outPtr, maxBytesToWrite) => { - return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); - }; - - - - - var __embind_register_std_string = (rawType, name) => { + function __embind_register_std_string(rawType, name) { name = readLatin1String(name); var stdStringIsUTF8 //process only std::string bindings with UTF8 support, in contrast to e.g. std::basic_string = (name === "std::string"); registerType(rawType, { - name, - // For some method names we use string keys here since they are part of - // the public/external API and/or used by the runtime-generated code. - 'fromWireType'(value) { - var length = HEAPU32[((value)>>2)]; - var payload = value + 4; - - var str; - if (stdStringIsUTF8) { - var decodeStartPtr = payload; - // Looping here to support possible embedded '0' bytes - for (var i = 0; i <= length; ++i) { - var currentBytePtr = payload + i; - if (i == length || HEAPU8[currentBytePtr] == 0) { - var maxRead = currentBytePtr - decodeStartPtr; - var stringSegment = UTF8ToString(decodeStartPtr, maxRead); - if (str === undefined) { - str = stringSegment; - } else { - str += String.fromCharCode(0); - str += stringSegment; - } - decodeStartPtr = currentBytePtr + 1; + name: name, + 'fromWireType': function(value) { + var length = HEAPU32[value >> 2]; + + var str; + if (stdStringIsUTF8) { + var decodeStartPtr = value + 4; + // Looping here to support possible embedded '0' bytes + for (var i = 0; i <= length; ++i) { + var currentBytePtr = value + 4 + i; + if (i == length || HEAPU8[currentBytePtr] == 0) { + var maxRead = currentBytePtr - decodeStartPtr; + var stringSegment = UTF8ToString(decodeStartPtr, maxRead); + if (str === undefined) { + str = stringSegment; + } else { + str += String.fromCharCode(0); + str += stringSegment; + } + decodeStartPtr = currentBytePtr + 1; + } + } + } else { + var a = new Array(length); + for (var i = 0; i < length; ++i) { + a[i] = String.fromCharCode(HEAPU8[value + 4 + i]); + } + str = a.join(''); } - } - } else { - var a = new Array(length); - for (var i = 0; i < length; ++i) { - a[i] = String.fromCharCode(HEAPU8[payload + i]); - } - str = a.join(''); - } - - _free(value); - return str; - }, - 'toWireType'(destructors, value) { - if (value instanceof ArrayBuffer) { - value = new Uint8Array(value); - } + _free(value); - var length; - var valueIsOfTypeString = (typeof value == 'string'); + return str; + }, + 'toWireType': function(destructors, value) { + if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); + } - if (!(valueIsOfTypeString || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int8Array)) { - throwBindingError('Cannot pass non-string to std::string'); - } - if (stdStringIsUTF8 && valueIsOfTypeString) { - length = lengthBytesUTF8(value); - } else { - length = value.length; - } + var getLength; + var valueIsOfTypeString = (typeof value == 'string'); - // assumes POINTER_SIZE alignment - var base = _malloc(4 + length + 1); - var ptr = base + 4; - HEAPU32[((base)>>2)] = length; - if (stdStringIsUTF8 && valueIsOfTypeString) { - stringToUTF8(value, ptr, length + 1); - } else { - if (valueIsOfTypeString) { - for (var i = 0; i < length; ++i) { - var charCode = value.charCodeAt(i); - if (charCode > 255) { - _free(ptr); - throwBindingError('String has UTF-16 code units that do not fit in 8 bits'); - } - HEAPU8[ptr + i] = charCode; + if (!(valueIsOfTypeString || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int8Array)) { + throwBindingError('Cannot pass non-string to std::string'); } - } else { - for (var i = 0; i < length; ++i) { - HEAPU8[ptr + i] = value[i]; + if (stdStringIsUTF8 && valueIsOfTypeString) { + getLength = () => lengthBytesUTF8(value); + } else { + getLength = () => value.length; } - } - } - if (destructors !== null) { - destructors.push(_free, base); - } - return base; - }, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': readPointer, - destructorFunction(ptr) { - _free(ptr); - }, + // assumes 4-byte alignment + var length = getLength(); + var ptr = _malloc(4 + length + 1); + HEAPU32[ptr >> 2] = length; + if (stdStringIsUTF8 && valueIsOfTypeString) { + stringToUTF8(value, ptr + 4, length + 1); + } else { + if (valueIsOfTypeString) { + for (var i = 0; i < length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode > 255) { + _free(ptr); + throwBindingError('String has UTF-16 code units that do not fit in 8 bits'); + } + HEAPU8[ptr + 4 + i] = charCode; + } + } else { + for (var i = 0; i < length; ++i) { + HEAPU8[ptr + 4 + i] = value[i]; + } + } + } + + if (destructors !== null) { + destructors.push(_free, ptr); + } + return ptr; + }, + 'argPackAdvance': 8, + 'readValueFromPointer': simpleReadValueFromPointer, + destructorFunction: function(ptr) { _free(ptr); }, }); - }; + } - - - - var UTF16Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf-16le') : undefined;; - var UTF16ToString = (ptr, maxBytesToRead) => { - var endPtr = ptr; - // 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. - var idx = endPtr >> 1; - var maxIdx = idx + maxBytesToRead / 2; - // If maxBytesToRead is not passed explicitly, it will be undefined, and this - // will always evaluate to true. This saves on code size. - while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; - endPtr = idx << 1; - - if (endPtr - ptr > 32 && UTF16Decoder) - return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); - - // Fallback: decode without UTF16Decoder - var str = ''; - - // If maxBytesToRead is not passed explicitly, it will be undefined, and the - // for-loop's condition will always evaluate to true. The loop is then - // terminated on the first null char. - for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { - var codeUnit = HEAP16[(((ptr)+(i*2))>>1)]; - if (codeUnit == 0) break; - // fromCharCode constructs a character from a UTF-16 code unit, so we can - // pass the UTF16 string right through. - str += String.fromCharCode(codeUnit); - } - - return str; - }; - - var stringToUTF16 = (str, outPtr, maxBytesToWrite) => { - // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. - maxBytesToWrite ??= 0x7FFFFFFF; - if (maxBytesToWrite < 2) return 0; - maxBytesToWrite -= 2; // Null terminator. - var startPtr = outPtr; - var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length; - for (var i = 0; i < numCharsToWrite; ++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)>>1)] = codeUnit; - outPtr += 2; - } - // Null-terminate the pointer to the HEAP. - HEAP16[((outPtr)>>1)] = 0; - return outPtr - startPtr; - }; - - var lengthBytesUTF16 = (str) => { - return str.length*2; - }; - - var UTF32ToString = (ptr, maxBytesToRead) => { - var i = 0; - - var str = ''; - // If maxBytesToRead is not passed explicitly, it will be undefined, and this - // will always evaluate to true. This saves on code size. - while (!(i >= maxBytesToRead / 4)) { - var utf32 = HEAP32[(((ptr)+(i*4))>>2)]; - if (utf32 == 0) break; - ++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. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - if (utf32 >= 0x10000) { - var ch = utf32 - 0x10000; - str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); - } else { - str += String.fromCharCode(utf32); - } - } - return str; - }; - - var stringToUTF32 = (str, outPtr, maxBytesToWrite) => { - // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. - maxBytesToWrite ??= 0x7FFFFFFF; - if (maxBytesToWrite < 4) return 0; - var startPtr = outPtr; - var endPtr = startPtr + maxBytesToWrite - 4; - 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! We must decode the string to UTF-32 to the heap. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var codeUnit = str.charCodeAt(i); // possibly a lead surrogate - if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) { - var trailSurrogate = str.charCodeAt(++i); - codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); - } - HEAP32[((outPtr)>>2)] = codeUnit; - outPtr += 4; - if (outPtr + 4 > endPtr) break; - } - // Null-terminate the pointer to the HEAP. - HEAP32[((outPtr)>>2)] = 0; - return outPtr - startPtr; - }; - - var lengthBytesUTF32 = (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! We must decode the string to UTF-32 to the heap. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var codeUnit = str.charCodeAt(i); - if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate. - len += 4; - } - - return len; - }; - var __embind_register_std_wstring = (rawType, charSize, name) => { + function __embind_register_std_wstring(rawType, charSize, name) { name = readLatin1String(name); - var decodeString, encodeString, readCharAt, lengthBytesUTF; + var decodeString, encodeString, getHeap, lengthBytesUTF, shift; if (charSize === 2) { decodeString = UTF16ToString; encodeString = stringToUTF16; lengthBytesUTF = lengthBytesUTF16; - readCharAt = (pointer) => HEAPU16[((pointer)>>1)]; + getHeap = () => HEAPU16; + shift = 1; } else if (charSize === 4) { decodeString = UTF32ToString; encodeString = stringToUTF32; lengthBytesUTF = lengthBytesUTF32; - readCharAt = (pointer) => HEAPU32[((pointer)>>2)]; + getHeap = () => HEAPU32; + shift = 2; } registerType(rawType, { - name, - 'fromWireType': (value) => { + name: name, + 'fromWireType': function(value) { // Code mostly taken from _embind_register_std_string fromWireType - var length = HEAPU32[((value)>>2)]; + var length = HEAPU32[value >> 2]; + var HEAP = getHeap(); var str; var decodeStartPtr = value + 4; // Looping here to support possible embedded '0' bytes for (var i = 0; i <= length; ++i) { var currentBytePtr = value + 4 + i * charSize; - if (i == length || readCharAt(currentBytePtr) == 0) { + if (i == length || HEAP[currentBytePtr >> shift] == 0) { var maxReadBytes = currentBytePtr - decodeStartPtr; var stringSegment = decodeString(decodeStartPtr, maxReadBytes); if (str === undefined) { @@ -5445,15 +5766,15 @@ var tempI64; return str; }, - 'toWireType': (destructors, value) => { + 'toWireType': function(destructors, value) { if (!(typeof value == 'string')) { - throwBindingError(`Cannot pass non-string to C++ string type ${name}`); + throwBindingError('Cannot pass non-string to C++ string type ' + name); } - // assumes POINTER_SIZE alignment + // assumes 4-byte alignment var length = lengthBytesUTF(value); var ptr = _malloc(4 + length + charSize); - HEAPU32[((ptr)>>2)] = length / charSize; + HEAPU32[ptr >> 2] = length >> shift; encodeString(value, ptr + 4, length + charSize); @@ -5462,35 +5783,29 @@ var tempI64; } return ptr; }, - 'argPackAdvance': GenericWireTypeSize, - 'readValueFromPointer': readPointer, - destructorFunction(ptr) { - _free(ptr); - } + 'argPackAdvance': 8, + 'readValueFromPointer': simpleReadValueFromPointer, + destructorFunction: function(ptr) { _free(ptr); }, }); - }; + } - - - var __embind_register_value_object = ( + function __embind_register_value_object( rawType, name, constructorSignature, rawConstructor, destructorSignature, rawDestructor - ) => { + ) { structRegistrations[rawType] = { name: readLatin1String(name), rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), fields: [], }; - }; + } - - - var __embind_register_value_object_field = ( + function __embind_register_value_object_field( structType, fieldName, getterReturnType, @@ -5501,323 +5816,310 @@ var tempI64; setterSignature, setter, setterContext - ) => { + ) { structRegistrations[structType].fields.push({ fieldName: readLatin1String(fieldName), - getterReturnType, + getterReturnType: getterReturnType, getter: embind__requireFunction(getterSignature, getter), - getterContext, - setterArgumentType, + getterContext: getterContext, + setterArgumentType: setterArgumentType, setter: embind__requireFunction(setterSignature, setter), - setterContext, + setterContext: setterContext, }); - }; + } - - var __embind_register_void = (rawType, name) => { + function __embind_register_void(rawType, name) { name = readLatin1String(name); registerType(rawType, { - isVoid: true, // void return values can be optimized out sometimes - name, - 'argPackAdvance': 0, - 'fromWireType': () => undefined, - // TODO: assert if anything else is given? - 'toWireType': (destructors, o) => undefined, + isVoid: true, // void return values can be optimized out sometimes + name: name, + 'argPackAdvance': 0, + 'fromWireType': function() { + return undefined; + }, + 'toWireType': function(destructors, o) { + // TODO: assert if anything else is given? + return undefined; + }, }); - }; + } - var nowIsMonotonic = 1; - var __emscripten_get_now_is_monotonic = () => nowIsMonotonic; + function __emscripten_date_now() { + return Date.now(); + } - var __emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num); + var nowIsMonotonic = true;; + function __emscripten_get_now_is_monotonic() { + return nowIsMonotonic; + } - var __emscripten_throw_longjmp = () => { - throw Infinity; - }; + function __emscripten_throw_longjmp() { throw Infinity; } - - - var emval_returnValue = (returnType, destructorsRef, handle) => { - var destructors = []; - var result = returnType['toWireType'](destructors, handle); - if (destructors.length) { - // void, primitives and any other types w/o destructors don't need to allocate a handle - HEAPU32[((destructorsRef)>>2)] = Emval.toHandle(destructors); - } - return result; - }; - var __emval_as = (handle, returnType, destructorsRef) => { + function __emval_as(handle, returnType, destructorsRef) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); - return emval_returnValue(returnType, destructorsRef, handle); - }; - - var emval_methodCallers = []; - - var __emval_call = (caller, handle, destructorsRef, args) => { - caller = emval_methodCallers[caller]; - handle = Emval.toValue(handle); - return caller(null, handle, destructorsRef, args); - }; + var destructors = []; + var rd = Emval.toHandle(destructors); + HEAP32[destructorsRef >> 2] = rd; + return returnType['toWireType'](destructors, handle); + } - var emval_symbols = { - }; + function __emval_allocateDestructors(destructorsRef) { + var destructors = []; + HEAP32[destructorsRef >> 2] = Emval.toHandle(destructors); + return destructors; + } - var getStringOrSymbol = (address) => { + var emval_symbols = {}; + function getStringOrSymbol(address) { var symbol = emval_symbols[address]; if (symbol === undefined) { return readLatin1String(address); } return symbol; - }; - + } - var __emval_call_method = (caller, objHandle, methodName, destructorsRef, args) => { + var emval_methodCallers = []; + function __emval_call_void_method(caller, handle, methodName, args) { caller = emval_methodCallers[caller]; - objHandle = Emval.toValue(objHandle); + handle = Emval.toValue(handle); methodName = getStringOrSymbol(methodName); - return caller(objHandle, objHandle[methodName], destructorsRef, args); - }; + caller(handle, methodName, null, args); + } - - - var emval_get_global = () => { + function emval_get_global() { if (typeof globalThis == 'object') { return globalThis; } return (function(){ return Function; })()('return this')(); - }; - var __emval_get_global = (name) => { + } + function __emval_get_global(name) { if (name===0) { return Emval.toHandle(emval_get_global()); } else { name = getStringOrSymbol(name); return Emval.toHandle(emval_get_global()[name]); } - }; + } - var emval_addMethodCaller = (caller) => { + function __emval_addMethodCaller(caller) { var id = emval_methodCallers.length; emval_methodCallers.push(caller); return id; - }; + } - var emval_lookupTypes = (argCount, argTypes) => { + function __emval_lookupTypes(argCount, argTypes) { var a = new Array(argCount); for (var i = 0; i < argCount; ++i) { - a[i] = requireRegisteredType(HEAPU32[(((argTypes)+(i * 4))>>2)], + a[i] = requireRegisteredType(HEAP32[(argTypes >> 2) + i], "parameter " + i); } return a; - }; - - - var reflectConstruct = Reflect.construct; - - - var __emval_get_method_caller = (argCount, argTypes, kind) => { - var types = emval_lookupTypes(argCount, argTypes); - var retType = types.shift(); - argCount--; // remove the shifted off return type - - var functionBody = - `return function (obj, func, destructorsRef, args) {\n`; + } - var offset = 0; - var argsList = []; // 'obj?, arg0, arg1, arg2, ... , argN' - if (kind === /* FUNCTION */ 0) { - argsList.push("obj"); + var emval_registeredMethods = []; + function __emval_get_method_caller(argCount, argTypes) { + var types = __emval_lookupTypes(argCount, argTypes); + var retType = types[0]; + var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; + var returnId = emval_registeredMethods[signatureName]; + if (returnId !== undefined) { + return returnId; } + var params = ["retType"]; var args = [retType]; - for (var i = 0; i < argCount; ++i) { - argsList.push("arg" + i); + + var argsList = ""; // 'arg0, arg1, arg2, ... , argN' + for (var i = 0; i < argCount - 1; ++i) { + argsList += (i !== 0 ? ", " : "") + "arg" + i; params.push("argType" + i); - args.push(types[i]); - functionBody += - ` var arg${i} = argType${i}.readValueFromPointer(args${offset ? "+" + offset : ""});\n`; - offset += types[i]['argPackAdvance']; + args.push(types[1 + i]); + } + + var functionName = makeLegalFunctionName("methodCaller_" + signatureName); + var functionBody = + "return function " + functionName + "(handle, name, destructors, args) {\n"; + + var offset = 0; + for (var i = 0; i < argCount - 1; ++i) { + functionBody += + " var arg" + i + " = argType" + i + ".readValueFromPointer(args" + (offset ? ("+"+offset) : "") + ");\n"; + offset += types[i + 1]['argPackAdvance']; } - var invoker = kind === /* CONSTRUCTOR */ 1 ? 'new func' : 'func.call'; functionBody += - ` var rv = ${invoker}(${argsList.join(", ")});\n`; + " var rv = handle[name](" + argsList + ");\n"; + for (var i = 0; i < argCount - 1; ++i) { + if (types[i + 1]['deleteObject']) { + functionBody += + " argType" + i + ".deleteObject(arg" + i + ");\n"; + } + } if (!retType.isVoid) { - params.push("emval_returnValue"); - args.push(emval_returnValue); - functionBody += - " return emval_returnValue(retType, destructorsRef, rv);\n"; + functionBody += + " return retType.toWireType(destructors, rv);\n"; } functionBody += - "};\n"; + "};\n"; params.push(functionBody); - var invokerFunction = newFunc(Function, params)(...args); - var functionName = `methodCaller<(${types.map(t => t.name).join(', ')}) => ${retType.name}>`; - return emval_addMethodCaller(createNamedFunction(functionName, invokerFunction)); - }; + var invokerFunction = new_(Function, params).apply(null, args); + returnId = __emval_addMethodCaller(invokerFunction); + emval_registeredMethods[signatureName] = returnId; + return returnId; + } - - var __emval_get_module_property = (name) => { + function __emval_get_module_property(name) { name = getStringOrSymbol(name); return Emval.toHandle(Module[name]); - }; + } - var __emval_get_property = (handle, key) => { + function __emval_get_property(handle, key) { handle = Emval.toValue(handle); key = Emval.toValue(key); return Emval.toHandle(handle[key]); - }; + } - var __emval_incref = (handle) => { - if (handle > 9) { - emval_handles[handle + 1] += 1; + function __emval_incref(handle) { + if (handle > 4) { + emval_handle_array[handle].refcount += 1; } - }; + } + function craftEmvalAllocator(argCount) { + /*This function returns a new function that looks like this: + function emval_allocator_3(constructor, argTypes, args) { + var argType0 = requireRegisteredType(HEAP32[(argTypes >> 2)], "parameter 0"); + var arg0 = argType0['readValueFromPointer'](args); + var argType1 = requireRegisteredType(HEAP32[(argTypes >> 2) + 1], "parameter 1"); + var arg1 = argType1['readValueFromPointer'](args + 8); + var argType2 = requireRegisteredType(HEAP32[(argTypes >> 2) + 2], "parameter 2"); + var arg2 = argType2['readValueFromPointer'](args + 16); + var obj = new constructor(arg0, arg1, arg2); + return Emval.toHandle(obj); + } */ + var argsList = ""; + for (var i = 0; i < argCount; ++i) { + argsList += (i!==0?", ":"")+"arg"+i; // 'arg0, arg1, ..., argn' + } - var __emval_new_cstring = (v) => Emval.toHandle(getStringOrSymbol(v)); - + var functionBody = + "return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n"; + + for (var i = 0; i < argCount; ++i) { + functionBody += + "var argType"+i+" = requireRegisteredType(Module['HEAP32'][(argTypes >>> 2) + "+i+"], \"parameter "+i+"\");\n" + + "var arg"+i+" = argType"+i+".readValueFromPointer(args);\n" + + "args += argType"+i+"['argPackAdvance'];\n"; + } + functionBody += + "var obj = new constructor("+argsList+");\n" + + "return valueToHandle(obj);\n" + + "}\n"; + + /*jshint evil:true*/ + return (new Function("requireRegisteredType", "Module", "valueToHandle", functionBody))( + requireRegisteredType, Module, Emval.toHandle); + } + + var emval_newers = {}; + function __emval_new(handle, argCount, argTypes, args) { + handle = Emval.toValue(handle); + var newer = emval_newers[argCount]; + if (!newer) { + newer = craftEmvalAllocator(argCount); + emval_newers[argCount] = newer; + } - var __emval_run_destructors = (handle) => { + return newer(handle, argTypes, args); + } + + function __emval_new_cstring(v) { + return Emval.toHandle(getStringOrSymbol(v)); + } + + function __emval_run_destructors(handle) { var destructors = Emval.toValue(handle); runDestructors(destructors); __emval_decref(handle); - }; + } - - - - - - var convertI32PairToI53Checked = (lo, hi) => { - return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; - }; - function __mmap_js(len,prot,flags,fd,offset_low, offset_high,allocated,addr) { - var offset = convertI32PairToI53Checked(offset_low, offset_high); - - + function __mmap_js(len, prot, flags, fd, off, allocated) { try { - if (isNaN(offset)) return 61; - var stream = SYSCALLS.getStreamFromFD(fd); - var res = FS.mmap(stream, len, offset, prot, flags); + var stream = FS.getStream(fd); + if (!stream) return -8; + var res = FS.mmap(stream, len, off, prot, flags); var ptr = res.ptr; HEAP32[((allocated)>>2)] = res.allocated; - HEAPU32[((addr)>>2)] = ptr; - return 0; + return ptr; } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return -e.errno; } - ; } - - function __munmap_js(addr,len,prot,flags,fd,offset_low, offset_high) { - var offset = convertI32PairToI53Checked(offset_low, offset_high); - - + function __munmap_js(addr, len, prot, flags, fd, offset) { try { - var stream = SYSCALLS.getStreamFromFD(fd); - if (prot & 2) { - SYSCALLS.doMsync(addr, stream, len, flags, offset); + var stream = FS.getStream(fd); + if (stream) { + if (prot & 2) { + SYSCALLS.doMsync(addr, stream, len, flags, offset); + } + FS.munmap(stream); } } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.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(); + function _abort() { + abort(''); + } - var getHeapMax = () => + function 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 _emscripten_get_heap_max = () => getHeapMax(); - - var _emscripten_get_now; - // Modern environment where performance.now() is supported: - // N.B. a shorter form "_emscripten_get_now = performance.now;" is - // unfortunately not allowed even in current browsers (e.g. FF Nightly 75). - _emscripten_get_now = () => performance.now(); + return 2147483648; + } + function _emscripten_get_heap_max() { + return getHeapMax(); + } + + var _emscripten_get_now;if (ENVIRONMENT_IS_NODE) { + _emscripten_get_now = () => { + var t = process['hrtime'](); + return t[0] * 1e3 + t[1] / 1e6; + }; + } else _emscripten_get_now = () => performance.now(); ; - - var growMemory = (size) => { - var b = wasmMemory.buffer; - var pages = (size - b.byteLength + 65535) / 65536; + function _emscripten_memcpy_big(dest, src, num) { + HEAPU8.copyWithin(dest, src, src + num); + } + + function emscripten_realloc_buffer(size) { 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(); + wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16); // .grow() takes a delta compared to the previous size + updateGlobalBufferAndViews(wasmMemory.buffer); return 1 /*success*/; } catch(e) { } // implicit 0 return to save code size (caller will cast "undefined" into 0 // anyhow) - }; - var _emscripten_resize_heap = (requestedSize) => { + } + function _emscripten_resize_heap(requestedSize) { var oldSize = HEAPU8.length; - // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. - requestedSize >>>= 0; + requestedSize = 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. @@ -5845,7 +6147,7 @@ var tempI64; return false; } - var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; + let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; // Loop through potential heap size increases. If we attempt a too eager // reservation that fails, cut down on the attempted size and reserve a @@ -5857,22 +6159,21 @@ var tempI64; var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); - var replacement = growMemory(newSize); + var replacement = emscripten_realloc_buffer(newSize); if (replacement) { return true; } } return false; - }; + } - var ENV = { - }; + var ENV = {}; - var getExecutableName = () => { + function getExecutableName() { return thisProgram || './this.program'; - }; - var getEnvStrings = () => { + } + function getEnvStrings() { if (!getEnvStrings.strings) { // Default values. // Browser language detection #8751 @@ -5896,39 +6197,33 @@ var tempI64; } var strings = []; for (var x in env) { - strings.push(`${x}=${env[x]}`); + 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) => { + } + function _environ_get(__environ, environ_buf) { var bufSize = 0; - getEnvStrings().forEach((string, i) => { + getEnvStrings().forEach(function(string, i) { var ptr = environ_buf + bufSize; HEAPU32[(((__environ)+(i*4))>>2)] = ptr; - stringToAscii(string, ptr); + writeAsciiToMemory(string, ptr); bufSize += string.length + 1; }); return 0; - }; + } - var _environ_sizes_get = (penviron_count, penviron_buf_size) => { + function _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); + strings.forEach(function(string) { + bufSize += string.length + 1; + }); HEAPU32[((penviron_buf_size)>>2)] = bufSize; return 0; - }; + } function _fd_close(fd) { try { @@ -5937,79 +6232,69 @@ var tempI64; FS.close(stream); return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } /** @param {number=} offset */ - var doReadv = (stream, iov, iovcnt, offset) => { + function 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); + 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; + HEAP32[((pnum)>>2)] = num; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } - - function _fd_seek(fd,offset_low, offset_high,whence,newOffset) { - var offset = convertI32PairToI53Checked(offset_low, offset_high); - - + function convertI32PairToI53Checked(lo, hi) { + return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; + } + function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { try { - if (isNaN(offset)) return 61; + var offset = convertI32PairToI53Checked(offset_low, offset_high); 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.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[((newOffset)>>2)] = tempI64[0],HEAP32[(((newOffset)+(4))>>2)] = tempI64[1]); + (tempI64 = [stream.position>>>0,(tempDouble=stream.position,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>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; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } - ; } /** @param {number=} offset */ - var doWritev = (stream, iov, iovcnt, offset) => { + function 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); + var curr = FS.write(stream, HEAP8,ptr, len, offset); if (curr < 0) return -1; ret += curr; - if (typeof offset != 'undefined') { - offset += curr; - } } return ret; - }; - + } function _fd_write(fd, iov, iovcnt, pnum) { try { @@ -6018,161 +6303,605 @@ var tempI64; HEAPU32[((pnum)>>2)] = num; return 0; } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e; return e.errno; } } + function _getTempRet0() { + return getTempRet0(); + } + + function _setTempRet0(val) { + setTempRet0(val); + } + + 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++]) { + // no-op + } + 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()) { + // we spill over to next month + 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 { + // we stay in current month + newDate.setDate(newDate.getDate()+days); + return newDate; + } + } + + return newDate; + } + function _strftime(s, maxsize, format, tm) { + // size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr); + // http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html + + 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 ? UTF8ToString(tm_zone) : '' + }; + + var pattern = UTF8ToString(format); + + // expand format + var EXPANSION_RULES_1 = { + '%c': '%a %b %d %H:%M:%S %Y', // Replaced by the locale's appropriate date and time representation - e.g., Mon Aug 3 14:02:01 2013 + '%D': '%m/%d/%y', // Equivalent to %m / %d / %y + '%F': '%Y-%m-%d', // Equivalent to %Y - %m - %d + '%h': '%b', // Equivalent to %b + '%r': '%I:%M:%S %p', // Replaced by the time in a.m. and p.m. notation + '%R': '%H:%M', // Replaced by the time in 24-hour notation + '%T': '%H:%M:%S', // Replaced by the time + '%x': '%m/%d/%y', // Replaced by the locale's appropriate date representation + '%X': '%H:%M:%S', // Replaced by the locale's appropriate time representation + // Modified Conversion Specifiers + '%Ec': '%c', // Replaced by the locale's alternative appropriate date and time representation. + '%EC': '%C', // Replaced by the name of the base year (period) in the locale's alternative representation. + '%Ex': '%m/%d/%y', // Replaced by the locale's alternative date representation. + '%EX': '%H:%M:%S', // Replaced by the locale's alternative time representation. + '%Ey': '%y', // Replaced by the offset from %EC (year only) in the locale's alternative representation. + '%EY': '%Y', // Replaced by the full alternative year representation. + '%Od': '%d', // Replaced by the day of the month, using the locale's alternative numeric symbols, filled as needed with leading zeros if there is any alternative symbol for zero; otherwise, with leading characters. + '%Oe': '%e', // Replaced by the day of the month, using the locale's alternative numeric symbols, filled as needed with leading characters. + '%OH': '%H', // Replaced by the hour (24-hour clock) using the locale's alternative numeric symbols. + '%OI': '%I', // Replaced by the hour (12-hour clock) using the locale's alternative numeric symbols. + '%Om': '%m', // Replaced by the month using the locale's alternative numeric symbols. + '%OM': '%M', // Replaced by the minutes using the locale's alternative numeric symbols. + '%OS': '%S', // Replaced by the seconds using the locale's alternative numeric symbols. + '%Ou': '%u', // Replaced by the weekday as a number in the locale's alternative representation (Monday=1). + '%OU': '%U', // Replaced by the week number of the year (Sunday as the first day of the week, rules corresponding to %U ) using the locale's alternative numeric symbols. + '%OV': '%V', // Replaced by the week number of the year (Monday as the first day of the week, rules corresponding to %V ) using the locale's alternative numeric symbols. + '%Ow': '%w', // Replaced by the number of the weekday (Sunday=0) using the locale's alternative numeric symbols. + '%OW': '%W', // Replaced by the week number of the year (Monday as the first day of the week) using the locale's alternative numeric symbols. + '%Oy': '%y', // Replaced by the year (offset from %C ) using the locale's alternative numeric symbols. + }; + 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: // Sunday + return new Date(janFourth.getFullYear()-1, 11, 29); + case 1: // Monday + return janFourth; + case 2: // Tuesday + return new Date(janFourth.getFullYear(), 0, 3); + case 3: // Wednesday + return new Date(janFourth.getFullYear(), 0, 2); + case 4: // Thursday + return new Date(janFourth.getFullYear(), 0, 1); + case 5: // Friday + return new Date(janFourth.getFullYear()-1, 11, 31); + case 6: // Saturday + 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) { + // this date is after the start of the first week of this year + 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) { + // %g, %G, and %V give values according to the ISO 8601:2000 standard week-based year. + // In this system, weeks begin on a Monday and week 1 of the year is the week that includes + // January 4th, which is also the week that includes the first Thursday of the year, and + // is also the first week that contains at least four days in the year. + // If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of + // the last week of the preceding year; thus, for Saturday 2nd January 1999, + // %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th, + // or 31st is a Monday, it and any following days are part of week 1 of the following year. + // Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01. + + 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) { + // Day of the year (001-366) + 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) { + return date.tm_wday || 7; + }, + '%U': function(date) { + var days = date.tm_yday + 7 - date.tm_wday; + return leadingNulls(Math.floor(days / 7), 2); + }, + '%V': function(date) { + // Replaced by the week number of the year (Monday as the first day of the week) + // as a decimal number [01,53]. If the week containing 1 January has four + // or more days in the new year, then it is considered week 1. + // Otherwise, it is the last week of the previous year, and the next week is week 1. + // Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday] + var val = Math.floor((date.tm_yday + 7 - (date.tm_wday + 6) % 7 ) / 7); + // If 1 Jan is just 1-3 days past Monday, the previous week + // is also in this year. + if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) { + val++; + } + if (!val) { + val = 52; + // If 31 December of prev year a Thursday, or Friday of a + // leap year, then the prev year has 53 weeks. + var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7; + if (dec31 == 4 || (dec31 == 5 && __isLeapYear(date.tm_year%400-1))) { + val++; + } + } else if (val == 53) { + // If 1 January is not a Thursday, and not a Wednesday of a + // leap year, then this year has only 52 weeks. + var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7; + if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) + val = 1; + } + return leadingNulls(val, 2); + }, + '%w': function(date) { + return date.tm_wday; + }, + '%W': function(date) { + var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7); + return leadingNulls(Math.floor(days / 7), 2); + }, + '%y': function(date) { + // Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year] + return (date.tm_year+1900).toString().substring(2); + }, + '%Y': function(date) { + // Replaced by the year as a decimal number (for example, 1997). [ tm_year] + return date.tm_year+1900; + }, + '%z': function(date) { + // Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ). + // For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich). + var off = date.tm_gmtoff; + var ahead = off >= 0; + off = Math.abs(off) / 60; + // convert from minutes into hhmm format (which means 60 minutes = 100 units) + off = (off / 60)*100 + (off % 60); + return (ahead ? '+' : '-') + String("0000" + off).slice(-4); + }, + '%Z': function(date) { + return date.tm_zone; + }, + '%%': function() { + return '%'; + } + }; + + // Replace %% with a pair of NULLs (which cannot occur in a C string), then + // re-inject them after processing. + pattern = pattern.replace(/%%/g, '\0\0') + for (var rule in EXPANSION_RULES_2) { + if (pattern.includes(rule)) { + pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_2[rule](date)); + } + } + pattern = pattern.replace(/\0\0/g, '%') + + 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); // no locale support yet + } - FS.createPreloadedFile = FS_createPreloadedFile; + var FSNode = /** @constructor */ 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; + }; + var readMode = 292/*292*/ | 73/*73*/; + var writeMode = 146/*146*/; + Object.defineProperties(FSNode.prototype, { + read: { + get: /** @this{FSNode} */function() { + return (this.mode & readMode) === readMode; + }, + set: /** @this{FSNode} */function(val) { + val ? this.mode |= readMode : this.mode &= ~readMode; + } + }, + write: { + get: /** @this{FSNode} */function() { + return (this.mode & writeMode) === writeMode; + }, + set: /** @this{FSNode} */function(val) { + val ? this.mode |= writeMode : this.mode &= ~writeMode; + } + }, + isFolder: { + get: /** @this{FSNode} */function() { + return FS.isDir(this.mode); + } + }, + isDevice: { + get: /** @this{FSNode} */function() { + return FS.isChrdev(this.mode); + } + } + }); + FS.FSNode = FSNode; FS.staticInit();; -InternalError = Module['InternalError'] = class InternalError extends Error { constructor(message) { super(message); this.name = 'InternalError'; }}; +InternalError = Module['InternalError'] = extendError(Error, 'InternalError');; embind_init_charCodes(); -BindingError = Module['BindingError'] = class BindingError extends Error { constructor(message) { super(message); this.name = 'BindingError'; }}; +BindingError = Module['BindingError'] = extendError(Error, 'BindingError');; init_ClassHandle(); init_embind();; init_RegisteredPointer(); UnboundTypeError = Module['UnboundTypeError'] = extendError(Error, 'UnboundTypeError');; init_emval();; -var wasmImports = { - /** @export */ - __cxa_throw: ___cxa_throw, - /** @export */ - __syscall_fcntl64: ___syscall_fcntl64, - /** @export */ - __syscall_fstat64: ___syscall_fstat64, - /** @export */ - __syscall_ioctl: ___syscall_ioctl, - /** @export */ - __syscall_lstat64: ___syscall_lstat64, - /** @export */ - __syscall_newfstatat: ___syscall_newfstatat, - /** @export */ - __syscall_openat: ___syscall_openat, - /** @export */ - __syscall_stat64: ___syscall_stat64, - /** @export */ - _abort_js: __abort_js, - /** @export */ - _embind_finalize_value_object: __embind_finalize_value_object, - /** @export */ - _embind_register_bigint: __embind_register_bigint, - /** @export */ - _embind_register_bool: __embind_register_bool, - /** @export */ - _embind_register_class: __embind_register_class, - /** @export */ - _embind_register_class_constructor: __embind_register_class_constructor, - /** @export */ - _embind_register_class_function: __embind_register_class_function, - /** @export */ - _embind_register_constant: __embind_register_constant, - /** @export */ - _embind_register_emval: __embind_register_emval, - /** @export */ - _embind_register_enum: __embind_register_enum, - /** @export */ - _embind_register_enum_value: __embind_register_enum_value, - /** @export */ - _embind_register_float: __embind_register_float, - /** @export */ - _embind_register_function: __embind_register_function, - /** @export */ - _embind_register_integer: __embind_register_integer, - /** @export */ - _embind_register_memory_view: __embind_register_memory_view, - /** @export */ - _embind_register_std_string: __embind_register_std_string, - /** @export */ - _embind_register_std_wstring: __embind_register_std_wstring, - /** @export */ - _embind_register_value_object: __embind_register_value_object, - /** @export */ - _embind_register_value_object_field: __embind_register_value_object_field, - /** @export */ - _embind_register_void: __embind_register_void, - /** @export */ - _emscripten_get_now_is_monotonic: __emscripten_get_now_is_monotonic, - /** @export */ - _emscripten_memcpy_js: __emscripten_memcpy_js, - /** @export */ - _emscripten_throw_longjmp: __emscripten_throw_longjmp, - /** @export */ - _emval_as: __emval_as, - /** @export */ - _emval_call: __emval_call, - /** @export */ - _emval_call_method: __emval_call_method, - /** @export */ - _emval_decref: __emval_decref, - /** @export */ - _emval_get_global: __emval_get_global, - /** @export */ - _emval_get_method_caller: __emval_get_method_caller, - /** @export */ - _emval_get_module_property: __emval_get_module_property, - /** @export */ - _emval_get_property: __emval_get_property, - /** @export */ - _emval_incref: __emval_incref, - /** @export */ - _emval_new_cstring: __emval_new_cstring, - /** @export */ - _emval_run_destructors: __emval_run_destructors, - /** @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_heap_max: _emscripten_get_heap_max, - /** @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 */ - fd_close: _fd_close, - /** @export */ - fd_read: _fd_read, - /** @export */ - fd_seek: _fd_seek, - /** @export */ - fd_write: _fd_write, - /** @export */ - invoke_ii, - /** @export */ - invoke_vi, - /** @export */ - invoke_vii, - /** @export */ - invoke_viii +var ASSERTIONS = false; + + + +/** @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; +} + +function intArrayToString(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + var chr = array[i]; + if (chr > 0xFF) { + if (ASSERTIONS) { + assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.'); + } + chr &= 0xFF; + } + ret.push(String.fromCharCode(chr)); + } + return ret.join(''); +} + + +var asmLibraryArg = { + "__cxa_allocate_exception": ___cxa_allocate_exception, + "__cxa_throw": ___cxa_throw, + "__syscall_fcntl64": ___syscall_fcntl64, + "__syscall_fstat64": ___syscall_fstat64, + "__syscall_ioctl": ___syscall_ioctl, + "__syscall_lstat64": ___syscall_lstat64, + "__syscall_newfstatat": ___syscall_newfstatat, + "__syscall_openat": ___syscall_openat, + "__syscall_stat64": ___syscall_stat64, + "_embind_finalize_value_object": __embind_finalize_value_object, + "_embind_register_bigint": __embind_register_bigint, + "_embind_register_bool": __embind_register_bool, + "_embind_register_class": __embind_register_class, + "_embind_register_class_constructor": __embind_register_class_constructor, + "_embind_register_class_function": __embind_register_class_function, + "_embind_register_constant": __embind_register_constant, + "_embind_register_emval": __embind_register_emval, + "_embind_register_enum": __embind_register_enum, + "_embind_register_enum_value": __embind_register_enum_value, + "_embind_register_float": __embind_register_float, + "_embind_register_function": __embind_register_function, + "_embind_register_integer": __embind_register_integer, + "_embind_register_memory_view": __embind_register_memory_view, + "_embind_register_std_string": __embind_register_std_string, + "_embind_register_std_wstring": __embind_register_std_wstring, + "_embind_register_value_object": __embind_register_value_object, + "_embind_register_value_object_field": __embind_register_value_object_field, + "_embind_register_void": __embind_register_void, + "_emscripten_date_now": __emscripten_date_now, + "_emscripten_get_now_is_monotonic": __emscripten_get_now_is_monotonic, + "_emscripten_throw_longjmp": __emscripten_throw_longjmp, + "_emval_as": __emval_as, + "_emval_call_void_method": __emval_call_void_method, + "_emval_decref": __emval_decref, + "_emval_get_global": __emval_get_global, + "_emval_get_method_caller": __emval_get_method_caller, + "_emval_get_module_property": __emval_get_module_property, + "_emval_get_property": __emval_get_property, + "_emval_incref": __emval_incref, + "_emval_new": __emval_new, + "_emval_new_cstring": __emval_new_cstring, + "_emval_run_destructors": __emval_run_destructors, + "_mmap_js": __mmap_js, + "_munmap_js": __munmap_js, + "abort": _abort, + "emscripten_get_heap_max": _emscripten_get_heap_max, + "emscripten_get_now": _emscripten_get_now, + "emscripten_memcpy_big": _emscripten_memcpy_big, + "emscripten_resize_heap": _emscripten_resize_heap, + "environ_get": _environ_get, + "environ_sizes_get": _environ_sizes_get, + "fd_close": _fd_close, + "fd_read": _fd_read, + "fd_seek": _fd_seek, + "fd_write": _fd_write, + "getTempRet0": _getTempRet0, + "invoke_ii": invoke_ii, + "invoke_vi": invoke_vi, + "invoke_vii": invoke_vii, + "invoke_viii": invoke_viii, + "setTempRet0": _setTempRet0, + "strftime_l": _strftime_l +}; +var asm = createWasm(); +/** @type {function(...*):?} */ +var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() { + return (___wasm_call_ctors = Module["___wasm_call_ctors"] = Module["asm"]["__wasm_call_ctors"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _free = Module["_free"] = function() { + return (_free = Module["_free"] = Module["asm"]["free"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _malloc = Module["_malloc"] = function() { + return (_malloc = Module["_malloc"] = Module["asm"]["malloc"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _saveSetjmp = Module["_saveSetjmp"] = function() { + return (_saveSetjmp = Module["_saveSetjmp"] = Module["asm"]["saveSetjmp"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var ___getTypeName = Module["___getTypeName"] = function() { + return (___getTypeName = Module["___getTypeName"] = Module["asm"]["__getTypeName"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var ___embind_register_native_and_builtin_types = Module["___embind_register_native_and_builtin_types"] = function() { + return (___embind_register_native_and_builtin_types = Module["___embind_register_native_and_builtin_types"] = Module["asm"]["__embind_register_native_and_builtin_types"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var ___errno_location = Module["___errno_location"] = function() { + return (___errno_location = Module["___errno_location"] = Module["asm"]["__errno_location"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _emscripten_builtin_memalign = Module["_emscripten_builtin_memalign"] = function() { + return (_emscripten_builtin_memalign = Module["_emscripten_builtin_memalign"] = Module["asm"]["emscripten_builtin_memalign"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _setThrew = Module["_setThrew"] = function() { + return (_setThrew = Module["_setThrew"] = Module["asm"]["setThrew"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var stackSave = Module["stackSave"] = function() { + return (stackSave = Module["stackSave"] = Module["asm"]["stackSave"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var stackRestore = Module["stackRestore"] = function() { + return (stackRestore = Module["stackRestore"] = Module["asm"]["stackRestore"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var stackAlloc = Module["stackAlloc"] = function() { + return (stackAlloc = Module["stackAlloc"] = Module["asm"]["stackAlloc"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var ___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = function() { + return (___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = Module["asm"]["__cxa_is_pointer_type"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_ji = Module["dynCall_ji"] = function() { + return (dynCall_ji = Module["dynCall_ji"] = Module["asm"]["dynCall_ji"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_iij = Module["dynCall_iij"] = function() { + return (dynCall_iij = Module["dynCall_iij"] = Module["asm"]["dynCall_iij"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_jiiii = Module["dynCall_jiiii"] = function() { + return (dynCall_jiiii = Module["dynCall_jiiii"] = Module["asm"]["dynCall_jiiii"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_jiji = Module["dynCall_jiji"] = function() { + return (dynCall_jiji = Module["dynCall_jiji"] = Module["asm"]["dynCall_jiji"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_viijii = Module["dynCall_viijii"] = function() { + return (dynCall_viijii = Module["dynCall_viijii"] = Module["asm"]["dynCall_viijii"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_iiiiij = Module["dynCall_iiiiij"] = function() { + return (dynCall_iiiiij = Module["dynCall_iiiiij"] = Module["asm"]["dynCall_iiiiij"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_iiiiijj = Module["dynCall_iiiiijj"] = function() { + return (dynCall_iiiiijj = Module["dynCall_iiiiijj"] = Module["asm"]["dynCall_iiiiijj"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = function() { + return (dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = Module["asm"]["dynCall_iiiiiijj"]).apply(null, arguments); }; -var wasmExports = createWasm(); -var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports['__wasm_call_ctors'])(); -var ___getTypeName = (a0) => (___getTypeName = wasmExports['__getTypeName'])(a0); -var _free = (a0) => (_free = wasmExports['free'])(a0); -var _malloc = (a0) => (_malloc = wasmExports['malloc'])(a0); -var _emscripten_builtin_memalign = (a0, a1) => (_emscripten_builtin_memalign = wasmExports['emscripten_builtin_memalign'])(a0, a1); -var _setThrew = (a0, a1) => (_setThrew = wasmExports['setThrew'])(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 ___cxa_is_pointer_type = (a0) => (___cxa_is_pointer_type = wasmExports['__cxa_is_pointer_type'])(a0); -var dynCall_ji = Module['dynCall_ji'] = (a0, a1) => (dynCall_ji = Module['dynCall_ji'] = wasmExports['dynCall_ji'])(a0, a1); -var dynCall_iij = Module['dynCall_iij'] = (a0, a1, a2, a3) => (dynCall_iij = Module['dynCall_iij'] = wasmExports['dynCall_iij'])(a0, a1, a2, a3); -var dynCall_jiiii = Module['dynCall_jiiii'] = (a0, a1, a2, a3, a4) => (dynCall_jiiii = Module['dynCall_jiiii'] = wasmExports['dynCall_jiiii'])(a0, a1, a2, a3, a4); -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_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_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); + function invoke_vi(index,a1) { var sp = stackSave(); @@ -6219,21 +6948,35 @@ function invoke_vii(index,a1,a2) { } -// include: postamble.js -// === Auto-generated postamble setup entry stuff === +// === Auto-generated postamble setup entry stuff === + var calledRun; +/** + * @constructor + * @this {ExitStatus} + */ +function ExitStatus(status) { + this.name = "ExitStatus"; + this.message = "Program terminated with exit(" + status + ")"; + this.status = status; +} + +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 (!calledRun) run(); if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled }; -function run() { +/** @type {function(Array=)} */ +function run(args) { + args = args || arguments_; if (runDependencies > 0) { return; @@ -6258,7 +7001,7 @@ function run() { initRuntime(); readyPromiseResolve(Module); - Module['onRuntimeInitialized']?.(); + if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); postRun(); } @@ -6276,6 +7019,23 @@ function run() { doRun(); } } +Module['run'] = run; + +/** @param {boolean|number=} implicit */ +function exit(status, implicit) { + EXITSTATUS = status; + + procExit(status); +} + +function procExit(code) { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + if (Module['onExit']) Module['onExit'](code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); +} if (Module['preInit']) { if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; @@ -6286,26 +7046,19 @@ if (Module['preInit']) { 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; -// end include: postamble_modularize.js - return moduleRtn; + return BASIS.ready } ); })(); if (typeof exports === 'object' && typeof module === 'object') module.exports = BASIS; else if (typeof define === 'function' && define['amd']) - define([], () => BASIS); + define([], function() { return BASIS; }); +else if (typeof exports === 'object') + exports["BASIS"] = BASIS; diff --git a/webgl/encoder/build/basis_encoder.wasm b/webgl/encoder/build/basis_encoder.wasm old mode 100644 new mode 100755 index 1370787f..ed05a23b Binary files a/webgl/encoder/build/basis_encoder.wasm and b/webgl/encoder/build/basis_encoder.wasm differ diff --git a/webgl/transcoder/basis_wrappers.cpp b/webgl/transcoder/basis_wrappers.cpp index 4473626e..fd7ca23b 100644 --- a/webgl/transcoder/basis_wrappers.cpp +++ b/webgl/transcoder/basis_wrappers.cpp @@ -1315,6 +1315,86 @@ class basis_encoder return true; } + // Only works for LDR inputs. + bool set_slice_source_mipmap_image(uint32_t slice_index, uint32_t level_index, const emscripten::val& src_image_js_val, uint32_t src_image_width, uint32_t src_image_height, ldr_image_type img_type) + { + + if (level_index == 0) { + return set_slice_source_image(slice_index, src_image_js_val, src_image_width, src_image_height, img_type); + } + + + if (slice_index >= m_params.m_source_mipmap_images.size()) + { + m_params.m_source_mipmap_images.resize(slice_index + 1); + } + + if (level_index >= m_params.m_source_mipmap_images[slice_index].size()) + { + m_params.m_source_mipmap_images[slice_index].resize(level_index + 1); + } + + // First copy the src image buffer to the heap. + basisu::vector src_image_buf; + copy_from_jsbuffer(src_image_js_val, src_image_buf); + + // Now load the source image. + image& src_img = m_params.m_source_mipmap_images[slice_index][level_index]; + if (img_type == ldr_image_type::cPNGImage) + { + // It's a PNG file, so try and parse it. + if (!load_png(src_image_buf.data(), src_image_buf.size(), src_img, nullptr)) + { +#if BASISU_DEBUG_PRINTF + printf("basis_encoder::set_slice_source_mipmap_image: Failed parsing provided PNG file!\n"); +#endif + return false; + } + + src_image_width = src_img.get_width(); + src_image_height = src_img.get_height(); + } + else if (img_type == ldr_image_type::cJPGImage) + { + // It's a JPG file, so try and parse it. + if (!load_jpg(src_image_buf.data(), src_image_buf.size(), src_img)) + { +#if BASISU_DEBUG_PRINTF + printf("basis_encoder::set_slice_source_mipmap_image: Failed parsing provided JPG file!\n"); +#endif + return false; + } + + src_image_width = src_img.get_width(); + src_image_height = src_img.get_height(); + } + else if (img_type == ldr_image_type::cRGBA32) + { + // It's a raw image, so check the buffer's size. + if (src_image_buf.size() != src_image_width * src_image_height * sizeof(uint32_t)) + { +#if BASISU_DEBUG_PRINTF + printf("basis_encoder::set_slice_source_mipmap_image: Provided source buffer has an invalid size!\n"); +#endif + return false; + } + + // Copy the raw image's data into our source image. + src_img.resize(src_image_width, src_image_height); + memcpy(src_img.get_ptr(), src_image_buf.data(), src_image_width * src_image_height * sizeof(uint32_t)); + } + else + { +#if BASISU_DEBUG_PRINTF + printf("basis_encoder::set_slice_source_mipmap_image: Invalid img_type parameter\n"); +#endif + assert(0); + return false; + } + + return true; + } + // Accepts RGBA half float or RGBA float images, or .EXR, .HDR, .PNG, or .JPG file data. bool set_slice_source_image_hdr( uint32_t slice_index, @@ -1351,6 +1431,52 @@ class basis_encoder return true; } + bool set_slice_source_image_mipmap_hdr( + uint32_t slice_index, + uint32_t level_index, + const emscripten::val& src_image_js_val, + uint32_t src_image_width, uint32_t src_image_height, + hdr_image_type img_type, bool ldr_srgb_to_linear_conversion, float ldr_to_hdr_nit_multiplier) + { + assert(ldr_to_hdr_nit_multiplier > 0.0f); + + if (level_index == 0) { + return set_slice_source_image_hdr(slice_index, src_image_js_val, src_image_width, src_image_height, img_type, ldr_srgb_to_linear_conversion, ldr_to_hdr_nit_multiplier); + } + + if (slice_index >= m_params.m_source_mipmap_images_hdr.size()) + { + m_params.m_source_mipmap_images_hdr.resize(slice_index + 1); + } + + if (level_index >= m_params.m_source_mipmap_images_hdr[slice_index].size()) + { + m_params.m_source_mipmap_images_hdr[slice_index].resize(level_index + 1); + } + + // First copy the src image buffer to the heap. + basisu::vector src_image_buf; + copy_from_jsbuffer(src_image_js_val, src_image_buf); + + // Now load the source image. + imagef& src_img = m_params.m_source_mipmap_images_hdr[slice_index][level_index]; + + if (!load_image_hdr(src_image_buf.get_ptr(), src_image_buf.size(), src_img, src_image_width, src_image_height, img_type, ldr_srgb_to_linear_conversion, ldr_to_hdr_nit_multiplier)) + return false; + + if ((img_type == hdr_image_type::cHITPNGImage) || (img_type == hdr_image_type::cHITJPGImage)) + { + // Because we're loading the image ourselves we need to add these tags so the UI knows how to tone map LDR upconverted outputs. + // Normally basis_compressor adds them when it loads the images itself from source files. + basist::ktx2_add_key_value(m_params.m_ktx2_key_values, "LDRUpconversionMultiplier", fmt_string("{}", ldr_to_hdr_nit_multiplier)); + + if (ldr_srgb_to_linear_conversion) + basist::ktx2_add_key_value(m_params.m_ktx2_key_values, "LDRUpconversionSRGBToLinear", "1"); + } + + return true; + } + uint32_t encode(const emscripten::val& dst_basis_file_js_val) { if (!g_basis_initialized_flag) @@ -2282,6 +2408,10 @@ EMSCRIPTEN_BINDINGS(basis_codec) { return self.set_slice_source_image(slice_index, src_image_js_val, width, height, (ldr_image_type)img_type); })) + .function("setSliceSourceMipmapImage", optional_override([](basis_encoder& self, uint32_t slice_index, uint32_t level_index, const emscripten::val& src_image_js_val, uint32_t width, uint32_t height, uint32_t img_type) { + return self.set_slice_source_mipmap_image(slice_index, level_index, src_image_js_val, width, height, (ldr_image_type)img_type); + })) + .function("controlThreading", optional_override([](basis_encoder& self, bool enable_threading, uint32_t num_extra_worker_threads) { return self.control_threading(enable_threading, num_extra_worker_threads); })) @@ -2292,6 +2422,11 @@ EMSCRIPTEN_BINDINGS(basis_codec) { return self.set_slice_source_image_hdr(slice_index, src_image_js_val, width, height, (hdr_image_type)img_type, ldr_srgb_to_linear_conversion, ldr_to_hdr_nit_multiplier); })) + .function("setSliceSourceMipmapImageHDR", optional_override([](basis_encoder& self, uint32_t slice_index, uint32_t level_index, const emscripten::val& src_image_js_val, uint32_t width, uint32_t height, uint32_t img_type, + bool ldr_srgb_to_linear_conversion, float ldr_to_hdr_nit_multiplier) { + return self.set_slice_source_image_mipmap_hdr(slice_index, level_index, src_image_js_val, width, height, (hdr_image_type)img_type, ldr_srgb_to_linear_conversion, ldr_to_hdr_nit_multiplier); + })) + // Sets the desired encoding format. This is the preferred way to control which format the encoder creates. // tex_format is a basis_tex_format (cETC1s, cUASTC4x4, cUASTC_HDR_4x4 etc.) // This can be used instead of the older setUASTC(), setHDR() etc. methods.